{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Graphs and Networks in Linear Algebra\n", "\n", "This notebook is based on section 10.1 of Strang's *Linear Algebra* textbook.\n", "\n", "One interesting source of large matrices in linear algebra is a [graph](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics), a collection of *nodes* (vertices) and *edges* (arrows from one vertex to another). Graphs are used in many applications to represent *relationships* and *connectivity*, such as:\n", "\n", "* For computer networks, nodes could represent web pages, and edges could represent links.\n", "* For circuits, edges could represent wires (or resistors) and nodes junctions.\n", "* For transportation, nodes could represent cities and edges roads.\n", "* In bioinformatics, graphs can represent gene regulatory networks.\n", "* In sociology, nodes could represent people and edges relationships.\n", "* ... and many, many other applications ...\n", "\n", "In this notebook, we explain how a graph can be represented by a *matrix*, and how linear algebra can tell us properties of the graph and can help us do computations on graph-based problems. There is a particularly beautiful connection to Kirchhoff's laws of circuit theory." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Packages for this notebook\n", "\n", "To run the code in this notebook, you'll need to install a few Julia packages used below. To do so, uncomment the following line and run it:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Pkg.add.([\"LightGraphs\", \"MetaGraphs\", \"GraphPlot\", \"NamedColors\", \"RowEchelon\", Interact\", \"SymPy\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "...and then run this cell to import the packages:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " \n", " Unable to load WebIO. Please make sure WebIO works for your Jupyter client.\n", " \n", " \n" ], "text/plain": [ "HTML{String}(\" \\n \\n Unable to load WebIO. Please make sure WebIO works for your Jupyter client.\\n \\n \\n\")" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using Interact, RowEchelon, LightGraphs, MetaGraphs, GraphPlot, NamedColors, LinearAlgebra\n", "import SymPy\n", "using SymPy: Sym" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Julia Graph-visualization code\n", "\n", "There are several Julia packages for manipulating graphs, e.g. [LightGraphs](https://github.com/JuliaGraphs/LightGraphs.jl), along with several packages for visualizing graphs, e.g. [GraphViz](https://github.com/Keno/GraphViz.jl). LightGraphs is oriented towards fast and sophisticated graph computations, however, and here I just want to do some simple and pretty visualizations with simple algorithms based on those in Strang's 18.06 textbook.\n", "\n", "So, here I define a simple `MyGraph` wrapper around LightGraphs directed graphs, with metadata attached via the MetaGraphs package, for basic plotting via the GraphPlots package." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "labels (generic function with 1 method)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "struct MyGraph\n", " g::MetaDiGraph\n", "end\n", "Base.copy(mg::MyGraph) = MyGraph(copy(mg.g))\n", "function MyGraph(edges::Pair{<:Integer,<:Integer}...)\n", " g = SimpleDiGraphFromIterator(Edge(e) for e in edges)\n", " MyGraph(MetaDiGraph(g))\n", "end\n", "\n", "using Random\n", "function deterministic_spring_layout(g::AbstractGraph; seed::Integer=0, kws...)\n", " rng = MersenneTwister(seed)\n", " spring_layout(g, 2 .* rand(rng, nv(g)) .- 1.0, 2 .* rand(rng,nv(g)) .- 1.0; kws...)\n", "end\n", "function Base.show(io::IO, m::MIME\"image/svg+xml\", mg::MyGraph)\n", " show(io, m, \n", " gplot(mg.g, layout=deterministic_spring_layout,\n", " nodelabel=map(v -> get(MetaGraphs.props(mg.g, v), :label, v), vertices(mg.g)),\n", " nodefillc=map(v -> get(MetaGraphs.props(mg.g, v), :color, \"gray\"), vertices(mg.g)),\n", " edgelabel=map(ie -> get(MetaGraphs.props(mg.g, ie[2]), :label, ie[1]), enumerate(edges(mg.g))),\n", " edgestrokec=map(e -> get(MetaGraphs.props(mg.g, e), :color, \"lightgray\"), edges(mg.g)),\n", " ))\n", "end\n", "\n", "function nodecolors!(g::MyGraph, nodes::AbstractVector{<:Integer}, color::String=\"red\")\n", " for n in nodes\n", " set_prop!(g.g, n, :color, color)\n", " end\n", " g\n", "end\n", "nodecolors(g, nodes, color) = nodecolors!(copy(g), nodes, color)\n", "edgearr(g, e) = e\n", "edgearr(g, e::AbstractVector{<:Integer}) = collect(edges(g))[e]\n", "edgearr(g, e::AbstractVector{<:Pair}) = Edge.(e)\n", "function edgecolors!(g::MyGraph, edges::AbstractVector, color::String=\"red\")\n", " for e in edgearr(g.g, edges)\n", " set_prop!(g.g, e, :color, color)\n", " end\n", " g\n", "end\n", "edgecolors(g::MyGraph, edges::AbstractVector, color::String=\"red\") = edgecolors!(copy(g), edges, color)\n", "\n", "# A little code so that we can label graph nodes/edges with SymPy expressions.\n", "# convert strings like \"v_2 - v_0\" from SymPy to nicer Unicode strings like \"v₂ - v₀\"\n", "subchar(d::Integer) = Char(UInt32('₀')+d)\n", "subchar(c::Char) = subchar(UInt32(c)-UInt32('0'))\n", "subchar(s::String) = replace(s, r\"_[0-9]\" => s -> subchar(s[2]))\n", "labelstring(s::SymPy.Sym) = subchar(repr(\"text/plain\", s))\n", "labelstring(x) = x\n", "\n", "function labels!(g::MyGraph; edges=nothing, nodes=nothing)\n", " if edges !== nothing\n", " for (e,E) in zip(MetaGraphs.edges(g.g), edges)\n", " set_prop!(g.g, e, :label, labelstring(E))\n", " end\n", " end\n", " if nodes !== nothing\n", " for (n,N) in zip(vertices(g.g), nodes)\n", " set_prop!(g.g, n, :label, labelstring(N))\n", " end\n", " end\n", " g\n", "end\n", "labels(g::MyGraph; kws...) = labels!(copy(g); kws...)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "randgraph (generic function with 1 method)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# generate a random graph with a given average #edges per node\n", "function randgraph(numnodes::Integer, edgespernode::Real)\n", " p = edgespernode/numnodes # probability of each edge\n", " e = Vector{Pair{Int,Int}}()\n", " for i = 1:numnodes, j = 1:numnodes\n", " if i != j && rand() < p\n", " push!(e, i=>j)\n", " end\n", " end\n", " return MyGraph(e...)\n", "end" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "incidence (generic function with 1 method)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# returns the incidence matrix for g\n", "function incidence(g::MyGraph)\n", " A = zeros(Int, ne(g.g), nv(g.g))\n", " for (i,e) in enumerate(edges(g.g))\n", " A[i,e.src] = -1\n", " A[i,e.dst] = +1\n", " end\n", " return A\n", "end" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "leftnullspace (generic function with 1 method)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Find the loops in g by the simplest \"textbook\" manner:\n", "# get a basis for the left nullspace incidence matrix.\n", "# We do this via the rref form, rather than nullspace(A'), because\n", "# we want a \"nice\" basis of ±1 and 0 entries.\n", "function leftnullspace(g::MyGraph)\n", " A = incidence(g)\n", " R = rref(Matrix(A'))\n", " m, n = size(R)\n", " pivots = Int[]\n", " for i = 1:m\n", " j = findfirst(!iszero, R[i,:])\n", " j !== nothing && push!(pivots, j)\n", " end\n", " r = length(pivots) # rank\n", " free = Int[j for j=1:n if j ∉ pivots]\n", " N = zeros(Int, n, n-r)\n", " k = 0\n", " for (k,j) in enumerate(free)\n", " N[pivots, k] = -R[1:r, j]\n", " N[j, k] = 1\n", " end\n", " return N\n", "end" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tree (generic function with 1 method)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# color the edges of a spanning tree of g, by the textbook\n", "# method of finding the pivot rows of the incidence matrix\n", "function pivotrows(g::MyGraph)\n", " A = incidence(g)\n", " R = rref(Matrix(A'))\n", " m, n = size(R)\n", " pivots = Int[]\n", " for i = 1:m\n", " j = findfirst(!iszero, R[i,:])\n", " j !== nothing && push!(pivots, j)\n", " end\n", " return pivots\n", "end\n", "colortree(g::MyGraph, color::String=\"red\") = edgecolors(g, pivotrows(g), color)\n", "tree(g::MyGraph) = MyGraph(MetaDiGraph(SimpleDiGraphFromIterator(edgearr(g.g, pivotrows(g)))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graphs and incidence matrices\n", "\n", "Let's start by looking at an example graph with 6 nodes 8 edges. Computers are pretty good at drawing graphs for us:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = MyGraph(1=>4, 4=>5, 5=>6, 6=>3, 3=>2, 2=>1, 2=>6, 4=>6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A key way to represent a graph in linear algebra is the [incidence matrix](https://en.wikipedia.org/wiki/Incidence_matrix). As defined in Strang's textbook, this is a matrix where the **rows correspond to edges** and the **columns correspond to nodes**. (Some authors use the transpose of this instead.)\n", "\n", "In particular, in the row for each edge going **from node N to node M**, there is a **-1 in column N** and a **+1 in column N**.\n", "\n", "For example, the incidence matrix of the graph above is:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8×6 Array{Int64,2}:\n", " -1 0 0 1 0 0\n", " 1 -1 0 0 0 0\n", " 0 -1 0 0 0 1\n", " 0 1 -1 0 0 0\n", " 0 0 0 -1 1 0\n", " 0 0 0 -1 0 1\n", " 0 0 0 0 -1 1\n", " 0 0 1 0 0 -1" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = incidence(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is an interesting structure if you think about *loops* in the graph. For example, in the graph above there is a loop among nodes 6, 3, 2, via edges 4,3,8. Let's look at the rows of $A$ corresponding to those edges:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×6 Array{Int64,2}:\n", " 0 1 -1 0 0 0\n", " 0 -1 0 0 0 1\n", " 0 0 1 0 0 -1" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[[4,3,8],:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we **add these rows** we get **zero**:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×6 Adjoint{Int64,Array{Int64,1}}:\n", " 0 0 0 0 0 0" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[4,:]' + A[3,:]' + A[8,:]'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In general, it is easy to see that **any loop in the graph** corresponds to **dependent rows**: if we sum the rows going around the loop (with a minus sign for arrows in the wrong direction), we get zero.\n", "\n", "The reason is simple: we get a -1 in a column when we *leave* a node, and a +1 in the column when we *enter* a node. When we go around the loop, we leave and enter each node, so the sum is zero.\n", "\n", "But dependent rows correspond to **elements of the left nullspace**:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×6 Array{Int64,2}:\n", " 0 0 0 0 0 0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[0 0 1 1 0 0 0 1] * A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That means that the number of \"independent\" (primitive) loops in a graph is related to the **rank** of the incidence matrix, and the **independent rows of A have no loops**.\n", "\n", "Let's look at the row-reduced echelon (rref) form of $A^T$:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6×8 Array{Int64,2}:\n", " 1 0 0 0 0 -1 -1 0\n", " 0 1 0 0 0 -1 -1 0\n", " 0 0 1 0 0 1 1 -1\n", " 0 0 0 1 0 0 0 -1\n", " 0 0 0 0 1 0 -1 0\n", " 0 0 0 0 0 0 0 0" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Matrix{Int}(rref(Matrix(A')))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see that the rank of $A$ is 5:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rank(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This means that there are **five loop-free (independent) edges**, and there are **three** (8 - 5) primitive loops. Using the rref form of $A^T$, we can read off a basis for the left nullspace from the free columns (6,7,8):" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8×3 Array{Int64,2}:\n", " 1 1 0\n", " 1 1 0\n", " -1 -1 1\n", " 0 0 1\n", " 0 1 0\n", " 1 0 0\n", " 0 1 0\n", " 0 0 1" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N = leftnullspace(g)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6×3 Array{Int64,2}:\n", " 0 0 0\n", " 0 0 0\n", " 0 0 0\n", " 0 0 0\n", " 0 0 0\n", " 0 0 0" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A' * N" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's visualize these loops by plotting the edges in a different color (red) one by one,\n", "with help from the Interact package to give us an interactive widget:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "animloops (generic function with 1 method)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colorloop(g::MyGraph, n::Vector) = edgecolors!(edgecolors(g, findall(n .> 0), \"red\"), findall(n .< 0), \"blue\")\n", "function animloops(g::MyGraph)\n", " L = leftnullspace(g)\n", " @manipulate for loop in 1:size(L,2)\n", " colorloop(g, L[:,loop])\n", " end\n", "end" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "application/vnd.webio.node+json": { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "loop" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: value, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 3, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"changes\\\":0,\\\"value\\\":2}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-5e5894c4-4d5a-4120-94d2-9404bbe983c5\",\"id\":\"ob_02\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"value\"].subscribe((function (val){!(this.valueFromJulia[\"value\"]) ? (_webIOScope.setObservableValue({\"name\":\"value\",\"scope\":\"knockout-component-5e5894c4-4d5a-4120-94d2-9404bbe983c5\",\"id\":\"ob_01\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"value\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "value": [ "(function (val){return (val!=this.model[\"value\"]()) ? (this.valueFromJulia[\"value\"]=true, this.model[\"value\"](val)) : undefined})" ] }, "id": "knockout-component-5e5894c4-4d5a-4120-94d2-9404bbe983c5", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_02", "sync": false, "value": 0 }, "value": { "id": "ob_01", "sync": true, "value": 2 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "id": "ob_07", "name": "obs-node" }, "nodeType": "ObservableNode", "props": {}, "type": "node" } ], "instanceArgs": { "handlers": {}, "id": "scope-48d3cb39-301d-48b2-bf09-1d8d82dd38c9", "imports": { "data": [], "type": "async_block" }, "observables": { "obs-node": { "id": "ob_07", "sync": false, "value": { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "setInnerHtml": "\n\n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n 1\n \n \n \n \n 2\n \n \n \n \n 3\n \n \n \n \n 4\n \n \n \n \n 5\n \n \n \n \n 6\n \n \n \n \n 7\n \n \n \n \n 8\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n 1\n \n \n \n \n 2\n \n \n \n \n 3\n \n \n \n \n 4\n \n \n \n \n 5\n \n \n \n \n 6\n \n \n\n\n" }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": {}, "type": "node" }, "text/html": [ "\n", " \n", "\n" ], "text/plain": [ "Widget{:manipulate,Any}(OrderedDict{Symbol,Any}(:loop=>Widget{:slider,Int64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:value=>Observable{Int64} with 2 listeners. Value:\n", "2), Observable{Int64} with 2 listeners. Value:\n", "2, Scope(\"knockout-component-5e5894c4-4d5a-4120-94d2-9404bbe983c5\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"loop\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>3,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: value, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"value\"=>(Observable{Int64} with 2 listeners. Value:\n", "2, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"changes\\\\\\\":0,\\\\\\\"value\\\\\\\":2}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-5e5894c4-4d5a-4120-94d2-9404bbe983c5\\\",\\\"id\\\":\\\"ob_02\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"value\\\",\\\"scope\\\":\\\"knockout-component-5e5894c4-4d5a-4120-94d2-9404bbe983c5\\\",\\\"id\\\":\\\"ob_01\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"value\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"value\\\"]()) ? (this.valueFromJulia[\\\"value\\\"]=true, this.model[\\\"value\\\"](val)) : undefined})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope))), Observable{Any} with 0 listeners. Value:\n", "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)), nothing, getfield(Main, Symbol(\"##21#23\")){Observable{Any}}(Observable{Any} with 0 listeners. Value:\n", "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))))" ] }, "execution_count": 18, "metadata": { "application/vnd.webio.node+json": { "kernelId": "ce8f9bc2-a3f5-447e-9f03-bf67c5c9ae34" } }, "output_type": "execute_result" } ], "source": [ "animloops(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These three loops are **not the only loops** in the graph, but the **other loops can be made from combinations of these loops**. (Similarly, the columns of $N$ are not the *whole* left nullspace, they are just a **basis** for the n nullspace.\n", "\n", "For example, the loop between nodes 1-4-5-6-3-2 can be made by starting with 1-4-5-6-2 and \"adding\" the 6-3-2 loop.\n", "\n", "In this sense, a basis for the left nullspace of $A$ is a \"basis\" for the other loops in the graph: we say that they are \"primitive\" loops." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colorloop(g, N[:,2] + N[:,3]) # add two loops to make another loop" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is fun to do the same thing for bigger graphs, chosen at random:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "application/vnd.webio.node+json": { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "loop" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: value, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 9, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"changes\\\":0,\\\"value\\\":5}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-445c54a5-22cf-48aa-bc7e-a2492035de0f\",\"id\":\"ob_09\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"value\"].subscribe((function (val){!(this.valueFromJulia[\"value\"]) ? (_webIOScope.setObservableValue({\"name\":\"value\",\"scope\":\"knockout-component-445c54a5-22cf-48aa-bc7e-a2492035de0f\",\"id\":\"ob_08\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"value\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "value": [ "(function (val){return (val!=this.model[\"value\"]()) ? (this.valueFromJulia[\"value\"]=true, this.model[\"value\"](val)) : undefined})" ] }, "id": "knockout-component-445c54a5-22cf-48aa-bc7e-a2492035de0f", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_09", "sync": false, "value": 0 }, "value": { "id": "ob_08", "sync": true, "value": 5 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "id": "ob_14", "name": "obs-node" }, "nodeType": "ObservableNode", "props": {}, "type": "node" } ], "instanceArgs": { "handlers": {}, "id": "scope-ba6b7f48-6ba2-4e49-9d45-a33625603f5e", "imports": { "data": [], "type": "async_block" }, "observables": { "obs-node": { "id": "ob_14", "sync": false, "value": { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "setInnerHtml": "\n\n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n 1\n \n \n \n \n 2\n \n \n \n \n 3\n \n \n \n \n 4\n \n \n \n \n 5\n \n \n \n \n 6\n \n \n \n \n 7\n \n \n \n \n 8\n \n \n \n \n 9\n \n \n \n \n 10\n \n \n \n \n 11\n \n \n \n \n 12\n \n \n \n \n 13\n \n \n \n \n 14\n \n \n \n \n 15\n \n \n \n \n 16\n \n \n \n \n 17\n \n \n \n \n 18\n \n \n \n \n 19\n \n \n \n \n 20\n \n \n \n \n 21\n \n \n \n \n 22\n \n \n \n \n 23\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n 1\n \n \n \n \n 2\n \n \n \n \n 3\n \n \n \n \n 4\n \n \n \n \n 5\n \n \n \n \n 6\n \n \n \n \n 7\n \n \n \n \n 8\n \n \n \n \n 9\n \n \n \n \n 10\n \n \n \n \n 11\n \n \n \n \n 12\n \n \n \n \n 13\n \n \n \n \n 14\n \n \n \n \n 15\n \n \n\n\n" }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": {}, "type": "node" }, "text/html": [ "\n", " \n", "\n" ], "text/plain": [ "Widget{:manipulate,Any}(OrderedDict{Symbol,Any}(:loop=>Widget{:slider,Int64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:value=>Observable{Int64} with 2 listeners. Value:\n", "5), Observable{Int64} with 2 listeners. Value:\n", "5, Scope(\"knockout-component-445c54a5-22cf-48aa-bc7e-a2492035de0f\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"loop\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>9,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: value, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"value\"=>(Observable{Int64} with 2 listeners. Value:\n", "5, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"changes\\\\\\\":0,\\\\\\\"value\\\\\\\":5}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-445c54a5-22cf-48aa-bc7e-a2492035de0f\\\",\\\"id\\\":\\\"ob_09\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"value\\\",\\\"scope\\\":\\\"knockout-component-445c54a5-22cf-48aa-bc7e-a2492035de0f\\\",\\\"id\\\":\\\"ob_08\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"value\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"value\\\"]()) ? (this.valueFromJulia[\\\"value\\\"]=true, this.model[\\\"value\\\"](val)) : undefined})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope))), Observable{Any} with 0 listeners. Value:\n", "MyGraph({15, 23} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)), nothing, getfield(Main, Symbol(\"##21#23\")){Observable{Any}}(Observable{Any} with 0 listeners. Value:\n", "MyGraph({15, 23} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))))" ] }, "execution_count": 20, "metadata": { "application/vnd.webio.node+json": { "kernelId": "ce8f9bc2-a3f5-447e-9f03-bf67c5c9ae34" } }, "output_type": "execute_result" } ], "source": [ "gbig = randgraph(15, 2)\n", "animloops(gbig)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Conversely, the *independent* rows of $A$ (corresponding to the **pivot columns** of the rref form of $A^T$) form a **maximal set of edges with no loops**. A graph with no loops is called a [tree](https://en.wikipedia.org/wiki/Tree_(graph_theory)), and this particular tree is called a [spanning tree](https://en.wikipedia.org/wiki/Spanning_tree) because it touches all of (\"spans\") the nodes (assuming the graph is connected).\n", "\n", "Let's color the spanning tree (loop-free edges) of our example graph red:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colortree(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also discard all of the edges that are *not* in the spanning tree, and we are left with a more boring graph of *just* the spanning tree:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 5} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can do the same thing for our bigger random example:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", " \n", " \n", " 9\n", " \n", " \n", " \n", " \n", " 10\n", " \n", " \n", " \n", " \n", " 11\n", " \n", " \n", " \n", " \n", " 12\n", " \n", " \n", " \n", " \n", " 13\n", " \n", " \n", " \n", " \n", " 14\n", " \n", " \n", " \n", " \n", " 15\n", " \n", " \n", " \n", " \n", " 16\n", " \n", " \n", " \n", " \n", " 17\n", " \n", " \n", " \n", " \n", " 18\n", " \n", " \n", " \n", " \n", " 19\n", " \n", " \n", " \n", " \n", " 20\n", " \n", " \n", " \n", " \n", " 21\n", " \n", " \n", " \n", " \n", " 22\n", " \n", " \n", " \n", " \n", " 23\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", " \n", " \n", " 9\n", " \n", " \n", " \n", " \n", " 10\n", " \n", " \n", " \n", " \n", " 11\n", " \n", " \n", " \n", " \n", " 12\n", " \n", " \n", " \n", " \n", " 13\n", " \n", " \n", " \n", " \n", " 14\n", " \n", " \n", " \n", " \n", " 15\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({15, 23} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colortree(gbig)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", " \n", " \n", " 9\n", " \n", " \n", " \n", " \n", " 10\n", " \n", " \n", " \n", " \n", " 11\n", " \n", " \n", " \n", " \n", " 12\n", " \n", " \n", " \n", " \n", " 13\n", " \n", " \n", " \n", " \n", " 14\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", " \n", " \n", " 9\n", " \n", " \n", " \n", " \n", " 10\n", " \n", " \n", " \n", " \n", " 11\n", " \n", " \n", " \n", " \n", " 12\n", " \n", " \n", " \n", " \n", " 13\n", " \n", " \n", " \n", " \n", " 14\n", " \n", " \n", " \n", " \n", " 15\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({15, 14} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree(gbig)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we can make trees from even larger graphs, for fun:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", " \n", " \n", " 9\n", " \n", " \n", " \n", " \n", " 10\n", " \n", " \n", " \n", " \n", " 11\n", " \n", " \n", " \n", " \n", " 12\n", " \n", " \n", " \n", " \n", " 13\n", " \n", " \n", " \n", " \n", " 14\n", " \n", " \n", " \n", " \n", " 15\n", " \n", " \n", " \n", " \n", " 16\n", " \n", " \n", " \n", " \n", " 17\n", " \n", " \n", " \n", " \n", " 18\n", " \n", " \n", " \n", " \n", " 19\n", " \n", " \n", " \n", " \n", " 20\n", " \n", " \n", " \n", " \n", " 21\n", " \n", " \n", " \n", " \n", " 22\n", " \n", " \n", " \n", " \n", " 23\n", " \n", " \n", " \n", " \n", " 24\n", " \n", " \n", " \n", " \n", " 25\n", " \n", " \n", " \n", " \n", " 26\n", " \n", " \n", " \n", " \n", " 27\n", " \n", " \n", " \n", " \n", " 28\n", " \n", " \n", " \n", " \n", " 29\n", " \n", " \n", " \n", " \n", " 30\n", " \n", " \n", " \n", " \n", " 31\n", " \n", " \n", " \n", " \n", " 32\n", " \n", " \n", " \n", " \n", " 33\n", " \n", " \n", " \n", " \n", " 34\n", " \n", " \n", " \n", " \n", " 35\n", " \n", " \n", " \n", " \n", " 36\n", " \n", " \n", " \n", " \n", " 37\n", " \n", " \n", " \n", " \n", " 38\n", " \n", " \n", " \n", " \n", " 39\n", " \n", " \n", " \n", " \n", " 40\n", " \n", " \n", " \n", " \n", " 41\n", " \n", " \n", " \n", " \n", " 42\n", " \n", " \n", " \n", " \n", " 43\n", " \n", " \n", " \n", " \n", " 44\n", " \n", " \n", " \n", " \n", " 45\n", " \n", " \n", " \n", " \n", " 46\n", " \n", " \n", " \n", " \n", " 47\n", " \n", " \n", " \n", " \n", " 48\n", " \n", " \n", " \n", " \n", " 49\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " 1\n", " \n", " \n", " \n", " \n", " 2\n", " \n", " \n", " \n", " \n", " 3\n", " \n", " \n", " \n", " \n", " 4\n", " \n", " \n", " \n", " \n", " 5\n", " \n", " \n", " \n", " \n", " 6\n", " \n", " \n", " \n", " \n", " 7\n", " \n", " \n", " \n", " \n", " 8\n", " \n", " \n", " \n", " \n", " 9\n", " \n", " \n", " \n", " \n", " 10\n", " \n", " \n", " \n", " \n", " 11\n", " \n", " \n", " \n", " \n", " 12\n", " \n", " \n", " \n", " \n", " 13\n", " \n", " \n", " \n", " \n", " 14\n", " \n", " \n", " \n", " \n", " 15\n", " \n", " \n", " \n", " \n", " 16\n", " \n", " \n", " \n", " \n", " 17\n", " \n", " \n", " \n", " \n", " 18\n", " \n", " \n", " \n", " \n", " 19\n", " \n", " \n", " \n", " \n", " 20\n", " \n", " \n", " \n", " \n", " 21\n", " \n", " \n", " \n", " \n", " 22\n", " \n", " \n", " \n", " \n", " 23\n", " \n", " \n", " \n", " \n", " 24\n", " \n", " \n", " \n", " \n", " 25\n", " \n", " \n", " \n", " \n", " 26\n", " \n", " \n", " \n", " \n", " 27\n", " \n", " \n", " \n", " \n", " 28\n", " \n", " \n", " \n", " \n", " 29\n", " \n", " \n", " \n", " \n", " 30\n", " \n", " \n", " \n", " \n", " 31\n", " \n", " \n", " \n", " \n", " 32\n", " \n", " \n", " \n", " \n", " 33\n", " \n", " \n", " \n", " \n", " 34\n", " \n", " \n", " \n", " \n", " 35\n", " \n", " \n", " \n", " \n", " 36\n", " \n", " \n", " \n", " \n", " 37\n", " \n", " \n", " \n", " \n", " 38\n", " \n", " \n", " \n", " \n", " 39\n", " \n", " \n", " \n", " \n", " 40\n", " \n", " \n", " \n", " \n", " 41\n", " \n", " \n", " \n", " \n", " 42\n", " \n", " \n", " \n", " \n", " 43\n", " \n", " \n", " \n", " \n", " 44\n", " \n", " \n", " \n", " \n", " 45\n", " \n", " \n", " \n", " \n", " 46\n", " \n", " \n", " \n", " \n", " 47\n", " \n", " \n", " \n", " \n", " 48\n", " \n", " \n", " \n", " \n", " 49\n", " \n", " \n", " \n", " \n", " 50\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({50, 49} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree(randgraph(50, 8))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graphs and Kirchhoff's circuit laws\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An elegant application of the incidence matrix and its subspaces arises if we think of the graph as representing an **electrical circuit**:\n", "\n", "* Each edge represents a wire/resistor, with an unknown current $i$. The *direction* of the edge indicates the *sign convention* ($i>0$ indicates current flowing in the direction of the arrow).\n", "* Each node represents a junction, with an unknown voltage $v$.\n", "\n", "Let's visualize this by re-labeling our graph from above. We'll use the [SymPy](https://github.com/JuliaPy/SymPy.jl) package to allow us to do *symbolic* (not numeric) calculations with the incidence matrix." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " i₁\n", " \n", " \n", " \n", " \n", " i₂\n", " \n", " \n", " \n", " \n", " i₃\n", " \n", " \n", " \n", " \n", " i₄\n", " \n", " \n", " \n", " \n", " i₅\n", " \n", " \n", " \n", " \n", " i₆\n", " \n", " \n", " \n", " \n", " i₇\n", " \n", " \n", " \n", " \n", " i₈\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " v₁\n", " \n", " \n", " \n", " \n", " v₂\n", " \n", " \n", " \n", " \n", " v₃\n", " \n", " \n", " \n", " \n", " v₄\n", " \n", " \n", " \n", " \n", " v₅\n", " \n", " \n", " \n", " \n", " v₆\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labels(g, edges=[Sym(\"i_$i\") for i = 1:size(A,1)], nodes=[Sym(\"v_$i\") for i = 1:size(A,2)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Kirchhoff's voltage law (KVL)\n", "\n", "Let's start doing some linear algebra. What happens if we *multiply* our incidence matrix $A$ by a vector of voltages, one per node?" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[ \\left[ \\begin{array}{r}v_{1}\\\\v_{2}\\\\v_{3}\\\\v_{4}\\\\v_{5}\\\\v_{6}\\end{array} \\right] \\]" ], "text/plain": [ "6-element Array{Sym,1}:\n", " v_1\n", " v_2\n", " v_3\n", " v_4\n", " v_5\n", " v_6" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = [Sym(\"v_$i\") for i = 1:size(A,2)]" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8×6 Array{Int64,2}:\n", " -1 0 0 1 0 0\n", " 1 -1 0 0 0 0\n", " 0 -1 0 0 0 1\n", " 0 1 -1 0 0 0\n", " 0 0 0 -1 1 0\n", " 0 0 0 -1 0 1\n", " 0 0 0 0 -1 1\n", " 0 0 1 0 0 -1" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[ \\left[ \\begin{array}{r}- v_{1} + v_{4}\\\\v_{1} - v_{2}\\\\- v_{2} + v_{6}\\\\v_{2} - v_{3}\\\\- v_{4} + v_{5}\\\\- v_{4} + v_{6}\\\\- v_{5} + v_{6}\\\\v_{3} - v_{6}\\end{array} \\right] \\]" ], "text/plain": [ "8-element Array{Sym,1}:\n", " -v_1 + v_4\n", " v_1 - v_2\n", " -v_2 + v_6\n", " v_2 - v_3\n", " -v_4 + v_5\n", " -v_4 + v_6\n", " -v_5 + v_6\n", " v_3 - v_6" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What we get are the **voltage difference** (and in particular, the **voltage rise**) across each edge. It is easier to see this if we use the elements of $Av$ to directly label the edges of our graph:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " -v₁ + v₄\n", " \n", " \n", " \n", " \n", " v₁ - v₂\n", " \n", " \n", " \n", " \n", " -v₂ + v₆\n", " \n", " \n", " \n", " \n", " v₂ - v₃\n", " \n", " \n", " \n", " \n", " -v₄ + v₅\n", " \n", " \n", " \n", " \n", " -v₄ + v₆\n", " \n", " \n", " \n", " \n", " -v₅ + v₆\n", " \n", " \n", " \n", " \n", " v₃ - v₆\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " v₁\n", " \n", " \n", " \n", " \n", " v₂\n", " \n", " \n", " \n", " \n", " v₃\n", " \n", " \n", " \n", " \n", " v₄\n", " \n", " \n", " \n", " \n", " v₅\n", " \n", " \n", " \n", " \n", " v₆\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labels(g, edges=A*v, nodes=v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's ask the inverse question: **what voltage differences $d=Av$** can possibly arise? i.e. what $d$ are in $C(A)$? \n", "\n", "Remember, $A$ is **not full rank**: its rank is 5, but there are 8 rows (8 edges). So, $C(A)$ is 5-dimensional (\"missing\" three dimensions). Equivalently $C(A)$ is **orthogonal to the left nullspace**, which has three rows. What does this mean?\n", "\n", "Let's visualize the differences d:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " d₁\n", " \n", " \n", " \n", " \n", " d₂\n", " \n", " \n", " \n", " \n", " d₃\n", " \n", " \n", " \n", " \n", " d₄\n", " \n", " \n", " \n", " \n", " d₅\n", " \n", " \n", " \n", " \n", " d₆\n", " \n", " \n", " \n", " \n", " d₇\n", " \n", " \n", " \n", " \n", " d₈\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " v₁\n", " \n", " \n", " \n", " \n", " v₂\n", " \n", " \n", " \n", " \n", " v₃\n", " \n", " \n", " \n", " \n", " v₄\n", " \n", " \n", " \n", " \n", " v₅\n", " \n", " \n", " \n", " \n", " v₆\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = [Sym(\"d_$j\") for j = 1:size(A,1)]\n", "labels(g, edges=d, nodes=v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If $N$ is a basis for the left nullspace, we must have $N^T d = 0$, or:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[ \\left[ \\begin{array}{r}d_{1} + d_{2} - d_{3} + d_{6}\\\\d_{1} + d_{2} - d_{3} + d_{5} + d_{7}\\\\d_{3} + d_{4} + d_{8}\\end{array} \\right] \\]" ], "text/plain": [ "3-element Array{Sym,1}:\n", " d_1 + d_2 - d_3 + d_6\n", " d_1 + d_2 - d_3 + d_5 + d_7\n", " d_3 + d_4 + d_8" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N' * d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But what is this? Remember, each element of the left nullspace corresponded to a **loop in the graph**. Saying $N^T d = 0$, or $d \\perp N(A^T)$, is equivalent to saying that the **sum of the voltage rises around each loop = 0**.\n", "\n", "But this is precisely [Kirchhoff's voltage law](https://en.wikipedia.org/wiki/Kirchhoff's_circuit_laws) from circuit theory!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Kirchhoff's current law (KCL)\n", "\n", "To actually solve circuit problems, we need three additional ingredients:\n", "\n", "* The voltage difference $d$ must be divided by a resistance $R$ to get the *current* $i$ through that edge: $i = -d/R = -Yd$ (where $Y=1/R$ is the \"admittance\"), by [Ohm's law](https://en.wikipedia.org/wiki/Ohm's_law). Note that we need a minus sign to get the current in the direction of the arrow, since $d$ was the the voltage *rise* across the edge.\n", "\n", "* The sum of the currents $i$ entering each node must be zero, by Kirchhoff's current law (KCL).\n", "\n", "* To get a nontrivial solution, we need some kind of *source*: a battery or current source, to start currents flowing.\n", "\n", "How do we represent each one of these steps by linear-algebra operations?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Ohm's law\n", "\n", "To represent Ohm's law, we need to multiply the voltage differences $d=Av$ by a *diagonal matrix* of admittances:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[\\left[ \\begin{array}{rrrrrrrr}Y_{1}&0&0&0&0&0&0&0\\\\0&Y_{2}&0&0&0&0&0&0\\\\0&0&Y_{3}&0&0&0&0&0\\\\0&0&0&Y_{4}&0&0&0&0\\\\0&0&0&0&Y_{5}&0&0&0\\\\0&0&0&0&0&Y_{6}&0&0\\\\0&0&0&0&0&0&Y_{7}&0\\\\0&0&0&0&0&0&0&Y_{8}\\end{array}\\right]\\]" ], "text/plain": [ "8×8 Array{Sym,2}:\n", " Y_1 0 0 0 0 0 0 0\n", " 0 Y_2 0 0 0 0 0 0\n", " 0 0 Y_3 0 0 0 0 0\n", " 0 0 0 Y_4 0 0 0 0\n", " 0 0 0 0 Y_5 0 0 0\n", " 0 0 0 0 0 Y_6 0 0\n", " 0 0 0 0 0 0 Y_7 0\n", " 0 0 0 0 0 0 0 Y_8" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y = diagm(0=>[Sym(\"Y_$i\") for i = 1:size(A,1)])" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[ \\left[ \\begin{array}{r}Y_{1} d_{1}\\\\Y_{2} d_{2}\\\\Y_{3} d_{3}\\\\Y_{4} d_{4}\\\\Y_{5} d_{5}\\\\Y_{6} d_{6}\\\\Y_{7} d_{7}\\\\Y_{8} d_{8}\\end{array} \\right] \\]" ], "text/plain": [ "8-element Array{Sym,1}:\n", " Y_1*d_1\n", " Y_2*d_2\n", " Y_3*d_3\n", " Y_4*d_4\n", " Y_5*d_5\n", " Y_6*d_6\n", " Y_7*d_7\n", " Y_8*d_8" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y*d" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[ \\left[ \\begin{array}{r}- Y_{1} v_{1} + Y_{1} v_{4}\\\\Y_{2} v_{1} - Y_{2} v_{2}\\\\- Y_{3} v_{2} + Y_{3} v_{6}\\\\Y_{4} v_{2} - Y_{4} v_{3}\\\\- Y_{5} v_{4} + Y_{5} v_{5}\\\\- Y_{6} v_{4} + Y_{6} v_{6}\\\\- Y_{7} v_{5} + Y_{7} v_{6}\\\\Y_{8} v_{3} - Y_{8} v_{6}\\end{array} \\right] \\]" ], "text/plain": [ "8-element Array{Sym,1}:\n", " -Y_1*v_1 + Y_1*v_4\n", " Y_2*v_1 - Y_2*v_2\n", " -Y_3*v_2 + Y_3*v_6\n", " Y_4*v_2 - Y_4*v_3\n", " -Y_5*v_4 + Y_5*v_5\n", " -Y_6*v_4 + Y_6*v_6\n", " -Y_7*v_5 + Y_7*v_6\n", " Y_8*v_3 - Y_8*v_6" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y*A*v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Net current into each node\n", "\n", "Given the currents $i$, a little thought shows that the net current flowing into each node is precisely $A^T i$:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[ \\left[ \\begin{array}{r}- i_{1} + i_{2}\\\\- i_{2} - i_{3} + i_{4}\\\\- i_{4} + i_{8}\\\\i_{1} - i_{5} - i_{6}\\\\i_{5} - i_{7}\\\\i_{3} + i_{6} + i_{7} - i_{8}\\end{array} \\right] \\]" ], "text/plain": [ "6-element Array{Sym,1}:\n", " -i_1 + i_2\n", " -i_2 - i_3 + i_4\n", " -i_4 + i_8\n", " i_1 - i_5 - i_6\n", " i_5 - i_7\n", " i_3 + i_6 + i_7 - i_8" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "i = [Sym(\"i_$j\") for j=1:size(A,1)]\n", "A'*i" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " i₁\n", " \n", " \n", " \n", " \n", " i₂\n", " \n", " \n", " \n", " \n", " i₃\n", " \n", " \n", " \n", " \n", " i₄\n", " \n", " \n", " \n", " \n", " i₅\n", " \n", " \n", " \n", " \n", " i₆\n", " \n", " \n", " \n", " \n", " i₇\n", " \n", " \n", " \n", " \n", " i₈\n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " -i₁ + i₂\n", " \n", " \n", " \n", " \n", " -i₂ - i₃ + i₄\n", " \n", " \n", " \n", " \n", " -i₄ + i₈\n", " \n", " \n", " \n", " \n", " i₁ - i₅ - i₆\n", " \n", " \n", " \n", " \n", " i₅ - i₇\n", " \n", " \n", " \n", " \n", " i₃ + i₆ + i₇ - i₈\n", " \n", " \n", "\n", "\n" ], "text/plain": [ "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labels(g, edges=i, nodes=A'*i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Why is this? The reason is that each row $A^T$ corresponds to a node, and has $\\pm 1$ for each edge going into or out of the node, exactly the right sign to sum the net currents flowing in:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6×8 Adjoint{Int64,Array{Int64,2}}:\n", " -1 1 0 0 0 0 0 0\n", " 0 -1 -1 1 0 0 0 0\n", " 0 0 0 -1 0 0 0 1\n", " 1 0 0 0 -1 -1 0 0\n", " 0 0 0 0 1 0 -1 0\n", " 0 0 1 0 0 1 1 -1" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Putting it together, given voltages $v$, the net current flowing **out of** each node is\n", "\n", "$$\n", "A^T Y A v\n", "$$\n", "\n", "The matrix $A^T Y A$ is a very special and important kind of matrix. It is obviously **symmetric**, and later on in the course we will see that any matrix of this form is necessarily **positive semidefinite** (all pivots are ≥ 0). Many important matrices in science, engineering, statistics, and other fields take on this special form.\n", "\n", "If we multiply $A^T Y A$ together, not all of its specialness is apparent. It is often better to leave it in \"factored\" form:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\[\\left[ \\begin{array}{rrrrrr}Y_{1} + Y_{2}&- Y_{2}&0&- Y_{1}&0&0\\\\- Y_{2}&Y_{2} + Y_{3} + Y_{4}&- Y_{4}&0&0&- Y_{3}\\\\0&- Y_{4}&Y_{4} + Y_{8}&0&0&- Y_{8}\\\\- Y_{1}&0&0&Y_{1} + Y_{5} + Y_{6}&- Y_{5}&- Y_{6}\\\\0&0&0&- Y_{5}&Y_{5} + Y_{7}&- Y_{7}\\\\0&- Y_{3}&- Y_{8}&- Y_{6}&- Y_{7}&Y_{3} + Y_{6} + Y_{7} + Y_{8}\\end{array}\\right]\\]" ], "text/plain": [ "6×6 Array{Sym,2}:\n", " Y_1 + Y_2 -Y_2 0 … 0 0\n", " -Y_2 Y_2 + Y_3 + Y_4 -Y_4 0 -Y_3\n", " 0 -Y_4 Y_4 + Y_8 0 -Y_8\n", " -Y_1 0 0 -Y_5 -Y_6\n", " 0 0 0 Y_5 + Y_7 -Y_7\n", " 0 -Y_3 -Y_8 … -Y_7 Y_3 + Y_6 + Y_7 + Y_8" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A' * Y * A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Null space\n", "\n", "If we just say that the net current flowing out of each node is zero, we get the equation:\n", "$$\n", "A^T Y A v = 0\n", "$$\n", "or $v \\in N(A^T Y A) = N(A)$.\n", "\n", "It is an amazing and important fact that $N(A^T Y A) = N(A)$!! (You saw a version of this in homework.) Why is this? Clearly, if $Ax = 0$ then $A^T Y Ax=0$. But what about the converse? Here is a trick: if $A^T Y Ax =0$, then $x^T A^T Y A x=0 = (Ax)^T Y (Ax)$. Let $y=Ax$. It is easy to see that $y^T Y y = \\sum_i Y_i y_i^2 = 0$ only if $y=0$, since all of the admittances $Y_i$ are positive. (We will later say that $Y$ is a \"positive-definite matrix\".) This means that $A^T Y Ax =0$ implies that $y=Ax=0$, which implies that $x \\in N(A)$.\n", "\n", "What is $N(A)$? The rank of $A$ is 5, so $N(A)$ must be **1-dimensional**. A basis for it is:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6×1 Array{Float64,2}:\n", " -0.4082482904638629 \n", " -0.408248290463863 \n", " -0.4082482904638628 \n", " -0.40824829046386313\n", " -0.4082482904638631 \n", " -0.4082482904638629 " ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nullspace(A)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "But this is, of course, just the space of vectors where **all voltages are equal**. In hindsight, this should be obvious: if all the voltages are equal, then their difference are zero, and the currents are zero, and KCL is satisfied." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Current sources\n", "\n", "Of course, it is much more interesting to think about circuits when the currents are nonzero!\n", "\n", "To do this, we must consider a **source term** in the equations, and in particular we could try to solve\n", "\n", "$$\n", "A^T Y A v = s\n", "$$\n", "\n", "for some $s\\ne 0$. What does $s$ represent? It is precisely an **external source of current** flowing **out of each node**.\n", "\n", "For this to have a solution, however, we must have $s \\in C(A^T Y A) = N((A^T Y A)^T)^\\perp = N(A^T Y A)^\\perp = N(A)^\\perp$ (since $A^T Y A$ is symmetric, the left and right nullspaces are equal). We know a basis for $N(A)$ from above, so this boils down to:\n", "\n", "$$\n", "\\begin{pmatrix} 1 & 1 & 1 & 1 & 1 & 1 \\end{pmatrix} s = 0 = \\sum_{i=1}^6 s_i\n", "$$\n", "\n", "That is, to have a solution, **all current that flows in must flow out**, so that the net current flowing into the circuit is zero. This makes a lot of physical sense!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just for fun, let's solve this circuit problem when the current is flowing **into node 2** and **out through node 1**, with slider controls for the 8 admittances, and label the edges with the currents." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "twodigits (generic function with 1 method)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "twodigits(x) = round(x, digits=2)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "application/vnd.webio.node+json": { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₁" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_17\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_19\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_18\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_16\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_18\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_17\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\",\"id\":\"ob_16\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_19", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_17", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_18", "sync": false, "value": "5.0" }, "index": { "id": "ob_16", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₂" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_22\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_24\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_23\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_21\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_23\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_22\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\",\"id\":\"ob_21\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_24", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_22", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_23", "sync": false, "value": "5.0" }, "index": { "id": "ob_21", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₃" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_27\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_29\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_28\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_26\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_28\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_27\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\",\"id\":\"ob_26\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_29", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_27", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_28", "sync": false, "value": "5.0" }, "index": { "id": "ob_26", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₄" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_32\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_34\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_33\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_31\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_33\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_32\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\",\"id\":\"ob_31\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_34", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_32", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_33", "sync": false, "value": "5.0" }, "index": { "id": "ob_31", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₅" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_37\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_39\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_38\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_36\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_38\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_37\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\",\"id\":\"ob_36\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_39", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_37", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_38", "sync": false, "value": "5.0" }, "index": { "id": "ob_36", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₆" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_42\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_44\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_43\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_41\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_43\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_42\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\",\"id\":\"ob_41\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-b277606f-985c-419d-b02e-511a141aa06b", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_44", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_42", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_43", "sync": false, "value": "5.0" }, "index": { "id": "ob_41", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₇" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_47\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_49\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_48\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_46\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_48\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_47\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\",\"id\":\"ob_46\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_49", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_47", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_48", "sync": false, "value": "5.0" }, "index": { "id": "ob_46", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [ { "children": [ { "children": [ { "children": [ "Y₈" ], "instanceArgs": { "namespace": "html", "tag": "label" }, "nodeType": "DOM", "props": { "className": "interact ", "style": { "padding": "5px 10px 0px 10px" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "text-align:right;width:18%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "input" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}", "orient": "horizontal", "type": "range" }, "className": "slider slider is-fullwidth", "max": 100, "min": 1, "step": 1, "style": {} }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "flex-grow:1; margin: 0 2%" } }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "p" }, "nodeType": "DOM", "props": { "attributes": { "data-bind": "text: formatted_value" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "width:18%" } }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } ], "instanceArgs": { "handlers": { "_promises": { "importsLoaded": [ "function (ko, koPunches) {\n ko.punches.enableAll();\n ko.bindingHandlers.numericValue = {\n init : function(element, valueAccessor, allBindings, data, context) {\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\n stringified.subscribe(function(value) {\n var val = parseFloat(value);\n if (!isNaN(val)) {\n valueAccessor()(val);\n }\n })\n valueAccessor().subscribe(function(value) {\n var str = JSON.stringify(value);\n if ((str == \"0\") && ([\"-0\", \"-0.\"].indexOf(stringified()) >= 0))\n return;\n if ([\"null\", \"\"].indexOf(str) >= 0)\n return;\n stringified(str);\n })\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\n }\n };\n var json_data = JSON.parse(\"{\\\"formatted_vals\\\":[\\\"0.1\\\",\\\"0.2\\\",\\\"0.3\\\",\\\"0.4\\\",\\\"0.5\\\",\\\"0.6\\\",\\\"0.7\\\",\\\"0.8\\\",\\\"0.9\\\",\\\"1.0\\\",\\\"1.1\\\",\\\"1.2\\\",\\\"1.3\\\",\\\"1.4\\\",\\\"1.5\\\",\\\"1.6\\\",\\\"1.7\\\",\\\"1.8\\\",\\\"1.9\\\",\\\"2.0\\\",\\\"2.1\\\",\\\"2.2\\\",\\\"2.3\\\",\\\"2.4\\\",\\\"2.5\\\",\\\"2.6\\\",\\\"2.7\\\",\\\"2.8\\\",\\\"2.9\\\",\\\"3.0\\\",\\\"3.1\\\",\\\"3.2\\\",\\\"3.3\\\",\\\"3.4\\\",\\\"3.5\\\",\\\"3.6\\\",\\\"3.7\\\",\\\"3.8\\\",\\\"3.9\\\",\\\"4.0\\\",\\\"4.1\\\",\\\"4.2\\\",\\\"4.3\\\",\\\"4.4\\\",\\\"4.5\\\",\\\"4.6\\\",\\\"4.7\\\",\\\"4.8\\\",\\\"4.9\\\",\\\"5.0\\\",\\\"5.1\\\",\\\"5.2\\\",\\\"5.3\\\",\\\"5.4\\\",\\\"5.5\\\",\\\"5.6\\\",\\\"5.7\\\",\\\"5.8\\\",\\\"5.9\\\",\\\"6.0\\\",\\\"6.1\\\",\\\"6.2\\\",\\\"6.3\\\",\\\"6.4\\\",\\\"6.5\\\",\\\"6.6\\\",\\\"6.7\\\",\\\"6.8\\\",\\\"6.9\\\",\\\"7.0\\\",\\\"7.1\\\",\\\"7.2\\\",\\\"7.3\\\",\\\"7.4\\\",\\\"7.5\\\",\\\"7.6\\\",\\\"7.7\\\",\\\"7.8\\\",\\\"7.9\\\",\\\"8.0\\\",\\\"8.1\\\",\\\"8.2\\\",\\\"8.3\\\",\\\"8.4\\\",\\\"8.5\\\",\\\"8.6\\\",\\\"8.7\\\",\\\"8.8\\\",\\\"8.9\\\",\\\"9.0\\\",\\\"9.1\\\",\\\"9.2\\\",\\\"9.3\\\",\\\"9.4\\\",\\\"9.5\\\",\\\"9.6\\\",\\\"9.7\\\",\\\"9.8\\\",\\\"9.9\\\",\\\"10.0\\\"],\\\"changes\\\":0,\\\"formatted_value\\\":\\\"5.0\\\",\\\"index\\\":50}\");\n var self = this;\n function AppViewModel() {\n for (var key in json_data) {\n var el = json_data[key];\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\n }\n \n \n [this[\"formatted_vals\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_vals\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_52\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_vals\"]=false}),self),this[\"changes\"].subscribe((function (val){!(this.valueFromJulia[\"changes\"]) ? (_webIOScope.setObservableValue({\"name\":\"changes\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_54\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"changes\"]=false}),self),this[\"formatted_value\"].subscribe((function (val){!(this.valueFromJulia[\"formatted_value\"]) ? (_webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_53\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"formatted_value\"]=false}),self),this[\"index\"].subscribe((function (val){!(this.valueFromJulia[\"index\"]) ? (_webIOScope.setObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_51\",\"type\":\"observable\"},val)) : undefined; return this.valueFromJulia[\"index\"]=false}),self)]\n \n }\n self.model = new AppViewModel();\n self.valueFromJulia = {};\n for (var key in json_data) {\n self.valueFromJulia[key] = false;\n }\n ko.applyBindings(self.model, self.dom);\n}\n" ] }, "changes": [ "(function (val){return (val!=this.model[\"changes\"]()) ? (this.valueFromJulia[\"changes\"]=true, this.model[\"changes\"](val)) : undefined})" ], "formatted_vals": [ "(function (val){return (val!=this.model[\"formatted_vals\"]()) ? (this.valueFromJulia[\"formatted_vals\"]=true, this.model[\"formatted_vals\"](val)) : undefined})" ], "formatted_value": [ "(function (val){return (val!=this.model[\"formatted_value\"]()) ? (this.valueFromJulia[\"formatted_value\"]=true, this.model[\"formatted_value\"](val)) : undefined})" ], "index": [ "(function (val){return (val!=this.model[\"index\"]()) ? (this.valueFromJulia[\"index\"]=true, this.model[\"index\"](val)) : undefined})", "(function (val){return _webIOScope.setObservableValue({\"name\":\"formatted_value\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_53\",\"type\":\"observable\"},_webIOScope.getObservableValue({\"name\":\"formatted_vals\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_52\",\"type\":\"observable\"})[(_webIOScope.getObservableValue({\"name\":\"index\",\"scope\":\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\",\"id\":\"ob_51\",\"type\":\"observable\"})-1)])})" ] }, "id": "knockout-component-358c62c2-31f6-4004-a037-4c6f56220441", "imports": { "data": [ { "name": "knockout", "type": "js", "url": "/assetserver/429ea4842967203db7a2e10862642c116542d0e4-knockout.js" }, { "name": "knockout_punches", "type": "js", "url": "/assetserver/9998dbb29ca780269e6886a8c8c4b78bb9a73c26-knockout_punches.js" }, { "name": null, "type": "js", "url": "/assetserver/6ee7ce3a8d8fbffe6a5785768ec923478100c144-all.js" }, { "name": null, "type": "css", "url": "/assetserver/255cc2d911924b0ffa0f74016aac5f640f90a396-style.css" }, { "name": null, "type": "css", "url": "/assetserver/66a9780e4509d09169a66d890937410d69e4da42-main.css" } ], "type": "async_block" }, "observables": { "changes": { "id": "ob_54", "sync": false, "value": 0 }, "formatted_vals": { "id": "ob_52", "sync": false, "value": [ "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8", "9.9", "10.0" ] }, "formatted_value": { "id": "ob_53", "sync": false, "value": "5.0" }, "index": { "id": "ob_51", "sync": true, "value": 50 } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "className": "field" }, "type": "node" }, { "children": [ { "children": [], "instanceArgs": { "id": "ob_59", "name": "obs-node" }, "nodeType": "ObservableNode", "props": {}, "type": "node" } ], "instanceArgs": { "handlers": {}, "id": "scope-0838b45e-2781-4a3e-9d5e-0aac5d2c7882", "imports": { "data": [], "type": "async_block" }, "observables": { "obs-node": { "id": "ob_59", "sync": false, "value": { "children": [ { "children": [], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "setInnerHtml": "\n\n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n i₁ = -0.3\n \n \n \n \n i₂ = 0.7\n \n \n \n \n i₃ = 0.2\n \n \n \n \n i₄ = -0.1\n \n \n \n \n i₅ = -0.1\n \n \n \n \n i₆ = -0.2\n \n \n \n \n i₇ = -0.1\n \n \n \n \n i₈ = -0.1\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n 1\n \n \n \n \n 2\n \n \n \n \n 3\n \n \n \n \n 4\n \n \n \n \n 5\n \n \n \n \n 6\n \n \n\n\n" }, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": { "attributes": { "style": "display:flex; justify-content:center; align-items:center;" } }, "type": "node" } } }, "systemjs_options": null }, "nodeType": "Scope", "props": {}, "type": "node" } ], "instanceArgs": { "namespace": "html", "tag": "div" }, "nodeType": "DOM", "props": {}, "type": "node" }, "text/html": [ "\n", " \n", "\n" ], "text/plain": [ "Widget{:manipulate,Any}(OrderedDict{Symbol,Any}(:Y₁=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₁\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_17\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_19\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_18\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_16\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_18\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_17\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-37f6044d-c8f8-407d-8d44-d8198f960e0e\\\",\\\"id\\\":\\\"ob_16\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₂=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₂\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_22\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_24\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_23\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_21\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_23\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_22\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-876c57af-f54e-4b21-9d4b-c1c8f06b3d49\\\",\\\"id\\\":\\\"ob_21\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₃=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₃\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_27\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_29\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_28\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_26\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_28\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_27\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-357cabbd-89fe-4f9b-9166-4c2fd4599e49\\\",\\\"id\\\":\\\"ob_26\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₄=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₄\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_32\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_34\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_33\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_31\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_33\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_32\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-70a9c1c0-2a3e-435f-bea7-89ddfc755348\\\",\\\"id\\\":\\\"ob_31\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₅=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₅\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_37\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_39\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_38\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_36\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_38\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_37\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-6c9c0868-bb9e-4e26-9a7a-857b4f61a1ce\\\",\\\"id\\\":\\\"ob_36\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₆=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₆\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_42\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_44\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_43\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_41\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_43\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_42\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-b277606f-985c-419d-b02e-511a141aa06b\\\",\\\"id\\\":\\\"ob_41\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₇=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₇\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_47\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_49\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_48\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_46\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_48\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_47\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-942adce0-9fe1-400b-80b6-82aa2544a456\\\",\\\"id\\\":\\\"ob_46\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope)),:Y₈=>Widget{:slider,Float64}(OrderedDict{Symbol,Any}(:changes=>Observable{Int64} with 1 listeners. Value:\n", "0,:index=>Observable{Any} with 2 listeners. Value:\n", "50,:formatted_vals=>Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"],:formatted_value=>Observable{String} with 1 listeners. Value:\n", "\"5.0\",:value=>Observable{Float64} with 2 listeners. Value:\n", "5.0), Observable{Float64} with 2 listeners. Value:\n", "5.0, Scope(\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\", Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :label), Any[\"Y₈\"], Dict{Symbol,Any}(:className=>\"interact \",:style=>Dict{Any,Any}(:padding=>\"5px 10px 0px 10px\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"text-align:right;width:18%\")), 2), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :input), Any[], Dict{Symbol,Any}(:max=>100,:min=>1,:attributes=>Dict{Any,Any}(:type=>\"range\",Symbol(\"data-bind\")=>\"numericValue: index, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}\",\"orient\"=>\"horizontal\"),:step=>1,:className=>\"slider slider is-fullwidth\",:style=>Dict{Any,Any}()), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"flex-grow:1; margin: 0 2%\")), 1), Node{DOM}(DOM(:html, :div), Any[Node{DOM}(DOM(:html, :p), Any[], Dict{Symbol,Any}(:attributes=>Dict(\"data-bind\"=>\"text: formatted_value\")), 0)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"width:18%\")), 1)], Dict{Symbol,Any}(:attributes=>Dict(\"style\"=>\"display:flex; justify-content:center; align-items:center;\")), 7), Dict{String,Tuple{Observables.AbstractObservable,Union{Nothing, Bool}}}(\"formatted_vals\"=>(Observable{Any} with 1 listeners. Value:\n", "[\"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\" … \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\"], nothing),\"changes\"=>(Observable{Int64} with 1 listeners. Value:\n", "0, nothing),\"formatted_value\"=>(Observable{String} with 1 listeners. Value:\n", "\"5.0\", nothing),\"index\"=>(Observable{Any} with 2 listeners. Value:\n", "50, nothing)), Set(String[]), nothing, Any[\"knockout\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout.js\", \"knockout_punches\"=>\"/Users/stevenj/.julia/packages/Knockout/JIqpG/src/../assets/knockout_punches.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/all.js\", \"/Users/stevenj/.julia/packages/InteractBase/Q4IkI/src/../assets/style.css\", \"/Users/stevenj/.julia/packages/InteractBulma/Ohu5Y/src/../assets/main.css\"], Dict{Any,Any}(\"formatted_vals\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_vals\\\"]()) ? (this.valueFromJulia[\\\"formatted_vals\\\"]=true, this.model[\\\"formatted_vals\\\"](val)) : undefined})\")],\"_promises\"=>Dict{Any,Any}(\"importsLoaded\"=>Any[JSString(\"function (ko, koPunches) {\\n ko.punches.enableAll();\\n ko.bindingHandlers.numericValue = {\\n init : function(element, valueAccessor, allBindings, data, context) {\\n var stringified = ko.observable(ko.unwrap(valueAccessor()));\\n stringified.subscribe(function(value) {\\n var val = parseFloat(value);\\n if (!isNaN(val)) {\\n valueAccessor()(val);\\n }\\n })\\n valueAccessor().subscribe(function(value) {\\n var str = JSON.stringify(value);\\n if ((str == \\\"0\\\") && ([\\\"-0\\\", \\\"-0.\\\"].indexOf(stringified()) >= 0))\\n return;\\n if ([\\\"null\\\", \\\"\\\"].indexOf(str) >= 0)\\n return;\\n stringified(str);\\n })\\n ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);\\n }\\n };\\n var json_data = JSON.parse(\\\"{\\\\\\\"formatted_vals\\\\\\\":[\\\\\\\"0.1\\\\\\\",\\\\\\\"0.2\\\\\\\",\\\\\\\"0.3\\\\\\\",\\\\\\\"0.4\\\\\\\",\\\\\\\"0.5\\\\\\\",\\\\\\\"0.6\\\\\\\",\\\\\\\"0.7\\\\\\\",\\\\\\\"0.8\\\\\\\",\\\\\\\"0.9\\\\\\\",\\\\\\\"1.0\\\\\\\",\\\\\\\"1.1\\\\\\\",\\\\\\\"1.2\\\\\\\",\\\\\\\"1.3\\\\\\\",\\\\\\\"1.4\\\\\\\",\\\\\\\"1.5\\\\\\\",\\\\\\\"1.6\\\\\\\",\\\\\\\"1.7\\\\\\\",\\\\\\\"1.8\\\\\\\",\\\\\\\"1.9\\\\\\\",\\\\\\\"2.0\\\\\\\",\\\\\\\"2.1\\\\\\\",\\\\\\\"2.2\\\\\\\",\\\\\\\"2.3\\\\\\\",\\\\\\\"2.4\\\\\\\",\\\\\\\"2.5\\\\\\\",\\\\\\\"2.6\\\\\\\",\\\\\\\"2.7\\\\\\\",\\\\\\\"2.8\\\\\\\",\\\\\\\"2.9\\\\\\\",\\\\\\\"3.0\\\\\\\",\\\\\\\"3.1\\\\\\\",\\\\\\\"3.2\\\\\\\",\\\\\\\"3.3\\\\\\\",\\\\\\\"3.4\\\\\\\",\\\\\\\"3.5\\\\\\\",\\\\\\\"3.6\\\\\\\",\\\\\\\"3.7\\\\\\\",\\\\\\\"3.8\\\\\\\",\\\\\\\"3.9\\\\\\\",\\\\\\\"4.0\\\\\\\",\\\\\\\"4.1\\\\\\\",\\\\\\\"4.2\\\\\\\",\\\\\\\"4.3\\\\\\\",\\\\\\\"4.4\\\\\\\",\\\\\\\"4.5\\\\\\\",\\\\\\\"4.6\\\\\\\",\\\\\\\"4.7\\\\\\\",\\\\\\\"4.8\\\\\\\",\\\\\\\"4.9\\\\\\\",\\\\\\\"5.0\\\\\\\",\\\\\\\"5.1\\\\\\\",\\\\\\\"5.2\\\\\\\",\\\\\\\"5.3\\\\\\\",\\\\\\\"5.4\\\\\\\",\\\\\\\"5.5\\\\\\\",\\\\\\\"5.6\\\\\\\",\\\\\\\"5.7\\\\\\\",\\\\\\\"5.8\\\\\\\",\\\\\\\"5.9\\\\\\\",\\\\\\\"6.0\\\\\\\",\\\\\\\"6.1\\\\\\\",\\\\\\\"6.2\\\\\\\",\\\\\\\"6.3\\\\\\\",\\\\\\\"6.4\\\\\\\",\\\\\\\"6.5\\\\\\\",\\\\\\\"6.6\\\\\\\",\\\\\\\"6.7\\\\\\\",\\\\\\\"6.8\\\\\\\",\\\\\\\"6.9\\\\\\\",\\\\\\\"7.0\\\\\\\",\\\\\\\"7.1\\\\\\\",\\\\\\\"7.2\\\\\\\",\\\\\\\"7.3\\\\\\\",\\\\\\\"7.4\\\\\\\",\\\\\\\"7.5\\\\\\\",\\\\\\\"7.6\\\\\\\",\\\\\\\"7.7\\\\\\\",\\\\\\\"7.8\\\\\\\",\\\\\\\"7.9\\\\\\\",\\\\\\\"8.0\\\\\\\",\\\\\\\"8.1\\\\\\\",\\\\\\\"8.2\\\\\\\",\\\\\\\"8.3\\\\\\\",\\\\\\\"8.4\\\\\\\",\\\\\\\"8.5\\\\\\\",\\\\\\\"8.6\\\\\\\",\\\\\\\"8.7\\\\\\\",\\\\\\\"8.8\\\\\\\",\\\\\\\"8.9\\\\\\\",\\\\\\\"9.0\\\\\\\",\\\\\\\"9.1\\\\\\\",\\\\\\\"9.2\\\\\\\",\\\\\\\"9.3\\\\\\\",\\\\\\\"9.4\\\\\\\",\\\\\\\"9.5\\\\\\\",\\\\\\\"9.6\\\\\\\",\\\\\\\"9.7\\\\\\\",\\\\\\\"9.8\\\\\\\",\\\\\\\"9.9\\\\\\\",\\\\\\\"10.0\\\\\\\"],\\\\\\\"changes\\\\\\\":0,\\\\\\\"formatted_value\\\\\\\":\\\\\\\"5.0\\\\\\\",\\\\\\\"index\\\\\\\":50}\\\");\\n var self = this;\\n function AppViewModel() {\\n for (var key in json_data) {\\n var el = json_data[key];\\n this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);\\n }\\n \\n \\n [this[\\\"formatted_vals\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_vals\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_52\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_vals\\\"]=false}),self),this[\\\"changes\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"changes\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"changes\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_54\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"changes\\\"]=false}),self),this[\\\"formatted_value\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"formatted_value\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_53\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"formatted_value\\\"]=false}),self),this[\\\"index\\\"].subscribe((function (val){!(this.valueFromJulia[\\\"index\\\"]) ? (_webIOScope.setObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_51\\\",\\\"type\\\":\\\"observable\\\"},val)) : undefined; return this.valueFromJulia[\\\"index\\\"]=false}),self)]\\n \\n }\\n self.model = new AppViewModel();\\n self.valueFromJulia = {};\\n for (var key in json_data) {\\n self.valueFromJulia[key] = false;\\n }\\n ko.applyBindings(self.model, self.dom);\\n}\\n\")]),\"changes\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"changes\\\"]()) ? (this.valueFromJulia[\\\"changes\\\"]=true, this.model[\\\"changes\\\"](val)) : undefined})\")],\"formatted_value\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"formatted_value\\\"]()) ? (this.valueFromJulia[\\\"formatted_value\\\"]=true, this.model[\\\"formatted_value\\\"](val)) : undefined})\")],\"index\"=>Any[JSString(\"(function (val){return (val!=this.model[\\\"index\\\"]()) ? (this.valueFromJulia[\\\"index\\\"]=true, this.model[\\\"index\\\"](val)) : undefined})\"), JSString(\"(function (val){return _webIOScope.setObservableValue({\\\"name\\\":\\\"formatted_value\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_53\\\",\\\"type\\\":\\\"observable\\\"},_webIOScope.getObservableValue({\\\"name\\\":\\\"formatted_vals\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_52\\\",\\\"type\\\":\\\"observable\\\"})[(_webIOScope.getObservableValue({\\\"name\\\":\\\"index\\\",\\\"scope\\\":\\\"knockout-component-358c62c2-31f6-4004-a037-4c6f56220441\\\",\\\"id\\\":\\\"ob_51\\\",\\\"type\\\":\\\"observable\\\"})-1)])})\")]), ConnectionPool(Channel{Any}(sz_max:9223372036854775807,sz_curr:0), Set(AbstractConnection[]), Channel{AbstractConnection}(sz_max:32,sz_curr:0))), ##52#53{#dom#13{##dom#11#12{Dict{Any,Any},DOM}},typeof(scope)}(#dom#13{##dom#11#12{Dict{Any,Any},DOM}}(##dom#11#12{Dict{Any,Any},DOM}(Dict{Any,Any}(:className=>\"field\"), DOM(:html, :div))), scope))), Observable{Any} with 0 listeners. Value:\n", "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)), nothing, getfield(Main, Symbol(\"##38#41\")){Observable{Any}}(Observable{Any} with 0 listeners. Value:\n", "MyGraph({6, 8} directed Int64 metagraph with Float64 weights defined by :weight (default weight 1.0))))" ] }, "execution_count": 42, "metadata": { "application/vnd.webio.node+json": { "kernelId": "ce8f9bc2-a3f5-447e-9f03-bf67c5c9ae34" } }, "output_type": "execute_result" } ], "source": [ "@manipulate for Y₁=0.1:0.1:10,\n", " Y₂=0.1:0.1:10,\n", " Y₃=0.1:0.1:10,\n", " Y₄=0.1:0.1:10,\n", " Y₅=0.1:0.1:10,\n", " Y₆=0.1:0.1:10,\n", " Y₇=0.1:0.1:10,\n", " Y₈=0.1:0.1:10\n", " s = [1,-1,0,0,0,0]\n", " Y = diagm(0=>[Y₁,Y₂,Y₃,Y₄,Y₅,Y₆,Y₇,Y₈])\n", " nodecolors!(labels(g, edges=[subchar(\"i_$j = $i\") for (j,i) in enumerate(twodigits.(Y*A*(pinv(A'*Y*A) * s)))]),\n", " [1,2])\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that if we make the admittance $Y_2$ really large compared to all of the other admittances, then nearly all of the current should flow just over that one edge. Conversely, if we make $Y_2$ really *small*, it is almost like \"cutting\" that wire: almost all of the current should flow through the *other* edges.\n", "\n", "Hooray, math (and physics) works!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sparsity\n", "\n", "The case of matrices arising from graphs illustrates another point that I've made many times: **really large matrices are often sparse (mostly 0)** in practice.\n", "\n", "For example, imagine a circuit with a million nodes. For the most part, there will only be *wires between nearby nodes*. Or imagine a graph where the nodes are websites and the edges are links: there are billions of sites, but *each site only links to a few other sites* (a few hundred at most, usually). In such cases, the **incidence matrix is mostly zero**, and similarly for $A^T Y A$ etcetetera.\n", "\n", "This is hugely important, because solving $Ax=b$ and most other matrix equations scale as $\\sim n^3$ for $n \\times n$ matrices. $1000 \\times 1000$ matrices are easy (< 1 second), but $n=10^6$ would require supercomputers, and $n=10^9$ would be impossibly hard. What saves us is that there are **much faster algorithms for sparse matrices**. We won't learn much about such algorithms in 18.06, but the key point is to know that they exist.\n", "\n", "If you encounter a large sparse matrix problem in the future, go read about sparse matrix algorithms!" ] } ], "metadata": { "@webio": { "lastCommId": "9339f69e893548cd885be5bb190b5104", "lastKernelId": "ce8f9bc2-a3f5-447e-9f03-bf67c5c9ae34" }, "anaconda-cloud": {}, "kernelspec": { "display_name": "Julia 1.0.1", "language": "julia", "name": "julia-1.0" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.0.1" } }, "nbformat": 4, "nbformat_minor": 1 }