diff --git a/src/LabGUI.jl b/src/LabGUI.jl
index f64a20e422936a28a2b7362a61bc9ec6ebff9119..a3bd69bd4b3518f554b216c5d5324e8633e9b74a 100644
--- a/src/LabGUI.jl
+++ b/src/LabGUI.jl
@@ -4,34 +4,6 @@ include("gridmaker.jl")
 include("gui.jl")
 include("construct.jl")
 include("svg_helper.jl")
+include("tools.jl")
 
-
-#We redefine WebIO.newid to prevent nodes from getting infinitely high values,
-# and Base.show is redefined to prevent memory leaks when constructing SVGs
-#=
-const max_nodes = 100000
-let count=1
-    global newid
-    node_space=Dict()
-    function WebIO.newid(prefix)
-        if count == max_nodes
-            count = 0
-        end
-        string(prefix, "-", count+=1)
-    end
-end
-
-function Base.show(io::IO, m::MIME"text/html", x::Node)
-    if haskey(x.props, :id)
-        id = "$(x.props[:id])-parent"
-    else
-        id = WebIO.newid("node")
-    end
-    x in keys(WebIO.showcbs) && (x = WebIO.showcbs[x](id))
-    write(io, """<div id=$id></div>
-          <script>WebIO.mount('$id', '#$id',""")
-    WebIO.jsexpr(io, x)
-    write(io, ")</script>")
-end
-=#
 end
diff --git a/src/gridmaker.jl b/src/gridmaker.jl
index 37adb3034d35506b080ab6c9fb7263ffebe8e24e..c382cc41d5bef2a65b73f21193ce082dabedca8b 100644
--- a/src/gridmaker.jl
+++ b/src/gridmaker.jl
@@ -9,6 +9,11 @@ function make_row(columns::Integer)
     (Node(:div, style=style, "Lorem Ipsum") for i in 1:columns)
 end
 
+"""
+Constructs a Node containing empty nodes in a row by column grid. A member can then be accessed using [n,m] syntax, but [n][m] accesses the element container; [n][m][1] is equivalent to [n,m]. This is done to maintain the style (width etc) of the subelements.
+
+"""
+
 function make_grid(rows::Integer, columns::Integer, width = 800, height = 1000)
     style_row  = Dict(:height => "$(100/rows)%", :overflow => "auto")
     style_grid = Dict(:width  => width, :height => height)
@@ -16,13 +21,6 @@ function make_grid(rows::Integer, columns::Integer, width = 800, height = 1000)
                                  for i in 1:rows)...)
 end
 
-#specify this later, should be some sort of typedef of WebIO.Node{WebIO.DOM}
-
-
-# We give the content of the container if given two arguments
-# If given one argument, we give the child
-# This means a[r,c] = a[r][c][1] and not a[r][c]
-# We to do this to keep the style (width and formatting of the columns)
 
 function Base.getindex(grid::WebIO.Node{WebIO.DOM}, ind::Integer)
     grid.children[ind]
@@ -32,8 +30,9 @@ function Base.getindex(grid::WebIO.Node{WebIO.DOM}, row::Integer, column::Intege
     grid[row][column][1]
 end
 
-
-
+"""
+WebIO.Node objects are immutable, so setindex_ simply returns a modified version of the original
+"""
 function setindex_(grid::WebIO.Node{WebIO.DOM},
                    new_value,
                   ind::Integer)
diff --git a/src/tools.jl b/src/tools.jl
new file mode 100644
index 0000000000000000000000000000000000000000..4769768971b17872b5ebefbc30b7cc5fd7d0a269
--- /dev/null
+++ b/src/tools.jl
@@ -0,0 +1,18 @@
+export link!
+"""
+Links the values of two observables by adding a listener. Optional arguments f and g specify transform of the value between the observables. If optional argument master=true all listeners of o2 are called if o1 is updated rather than just the value.
+
+Example:
+link(o1, o2, (x) -> 2*x, (x) -> x/2)
+will ensure obs(o2)[] is always 2*obs(o1)[] and vice versa.
+
+"""
+function link!(o1::Observable, o2::Observable, f = (x)->(x), g = (x)->(x), master=false)
+    if master
+        push!(o1.listeners, (x) -> o2[]=f(o1[]))
+    else
+        push!(o1.listeners, (x) -> o2.val=f(o1[]))
+    end
+    push!(o2.listeners, (x) -> o1.val = g(o2[]))
+end
+