diff --git a/doc/.gitignore b/doc/.gitignore
index df2a6e60dbf0dc336f4bc67ea1ef1b99119b2bda..28be7898ff6dfff29c153c7b0609b0d3918ee7ba 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -4,4 +4,5 @@ tech_report.blg
 tech_report.fdb_latexmk
 tech_report.fls
 tech_report.log
-tech_report.pdf
\ No newline at end of file
+tech_report.pdf
+tech_report.synctex.gz
\ No newline at end of file
diff --git a/lib/js/index.html b/lib/js/index.html
index 89acdf300a83041136f4f371d4604334135d784e..8c355c0b4103b5c43090e7db7b9231ce3040ac26 100644
--- a/lib/js/index.html
+++ b/lib/js/index.html
@@ -20,7 +20,7 @@ function decodeFromUrl(url) {
         if (arrayBuffer) {
             var buff = new LabComm.Buffer(new DataView(arrayBuffer));
             window.decoder = new LabComm.Decoder(function(decl, data) {
-                console.log(data);
+                testObject(data);
             });
             window.decoder.decodePackage(buff);
         }
@@ -35,6 +35,122 @@ btn.onclick = function() {
     decodeFromUrl(urlInp.value);
 };
 
+decodeFromUrl('http://fair-2014-4.lab1.cs.lth.se:8080/logdata/clamping/experiments/e12c4b31-5b32-41c0-b6a3-a5ad045aa997/data');
+
+
+var referenceObject = { 
+    log_message: { //struct
+        sequence: 10, //int
+        message: 'Test', //string
+        data: { //struct
+            f_value: 1.6, //float
+            d_value: 1000000.0, //double
+            l_value: 145, //long
+            s_value: 10, //short
+            b_value: 0xA, //byte
+            theStack: { //struct
+                level: 2, //int
+                name: 'Robot.Move.toPos(10)', //string
+                fatal: true //bool
+            }
+        },
+        xyz: [1,2,3], //int[3]
+        vect: [8,7,6,5,4,3], //int[_]
+        fix_mat: [[1,2,3,4],[2,3,4,5],[3,4,5,6]], //int[3][_]
+        dyn_mat: [[1,2],[3,4]], //int[_][2]
+        fix_mul: [[1,2,3,4],[2,3,4,5],[3,4,5,6]], //int[_, 4]
+        dyn_mul: [[1,2],[3,4]], //int[_, 2]
+        fix_mulmat: [[[1,2,3],[4,5,6]]], //int[1, _][_]
+        fix_matmul: [[[1,2,3],[4,5,6]]], //int[_][2, _]
+        dyn_mulmat: [[[1,2,3],[4,5,6]]], //int[_, _][3]
+        dyn_matmul: [[[1,2,3],[4,5,6]]], //int[1][_, 3]
+        points: [ 
+            {x: 4.6, y: 2.3},    
+            {x: 7.1, y: 1.0},    
+            {x: 6.2, y: 5.9}    
+        ] //struct { float x; float y; } points[_]
+    }
+};
+
+
+               
+
+
+function testObject(obj) {
+    console.log(JSON.stringify(obj));
+    console.log(compareObjects(referenceObject, obj));
+}
+
+function compareObjects(o, p) {
+    var i,
+        keysO = Object.keys(o).sort(),
+        keysP = Object.keys(p).sort();
+    if (keysO.length !== keysP.length) {
+        return false;//not the same nr of keys
+    }
+    if (keysO.join('') !== keysP.join('')) {
+        return false;//different keys
+    }
+    for (i=0;i<keysO.length;++i) {
+        var x = o[keysO[i]],
+            y = p[keysO[i]]; 
+        if (x instanceof Array) {
+            if (!(y instanceof Array))
+                return false;
+            //if (compareObjects(o[keysO[i]], p[keysO[i]] === false) return false
+            //would work, too, and perhaps is a better fit, still, this is easy, too
+            if (p[keysO[i]].sort().join('') !== o[keysO[i]].sort().join(''))
+                return false;
+        }
+        else if (o[keysO[i]] instanceof Date) {
+            if (!(p[keysO[i]] instanceof Date))
+                return false;
+            if ((''+o[keysO[i]]) !== (''+p[keysO[i]]))
+                return false;
+        }
+        else if (o[keysO[i]] instanceof Function) {
+            if (!(p[keysO[i]] instanceof Function))
+                return false;
+            //ignore functions, or check them regardless?
+        }
+        if (x instanceof Object) {
+            if (!(y instanceof Object))
+                return false;
+            if (x === o) {//self reference?
+                if (y !== p)
+                    return false;
+            }
+            else if (compareObjects(x, y) === false) {
+                return false;//WARNING: does not deal with circular refs other than ^^
+            }
+        }
+        else if(Number(x) === x) { //number
+            if((x|0) === x) { //int
+                if(x!==y) {
+                    return false;
+                }
+            }
+            else  {
+                //float point, allow deviation
+                var diff = Math.abs(x-y);
+                if(diff > 1e-6) {
+                    return false;
+                }
+            }
+        }
+        else if (x !== y) {//change !== to != for loose comparison
+            console.log('missmatch ' + x +':'+y);
+            return false;//not the same value
+        }
+
+
+        console.log('match ' + x +':'+y);
+    }
+    return true;
+}
+function isInt(n){
+        return Number(n)===n && n%1===0;
+}
     </script>
   </body>
 </html>
diff --git a/lib/js/lc.js b/lib/js/lc.js
index 4b87362c90357668d8e1201465645110d1682dd8..0182435b00c0f637ec504f48b3df0d8c19cac477 100644
--- a/lib/js/lc.js
+++ b/lib/js/lc.js
@@ -193,7 +193,7 @@ LabComm.Buffer.prototype.getDouble = function() {
  * @param {number} length The number of bytes to skip
  */
 LabComm.Buffer.prototype.skip = function(length) {
-    this.offset_ += len;
+    this.offset_ += length;
 };
 
 
@@ -218,14 +218,14 @@ LabComm.Decoder = function(callback) {
      * @private
      */
     this.callback_ = callback || function(a,b) {};
-};
 
-/**
- * A unique id for variable naming inside the decoder functions
- * @type {number}
- * @private
- */
-LabComm.Decoder.prototype.uid_ = 1;
+    /**
+     * A unique id for variable naming inside the decoder functions
+     * @type {number}
+     * @private
+     */
+    this.uid_ = 1;
+};
 
 /**
  * Builds a part of the decoder function
@@ -234,69 +234,182 @@ LabComm.Decoder.prototype.uid_ = 1;
  * @param {Array<string>} fb The final function body of the decoder
  * @param {string} type The string representation of the type
  * @param {string} parser The parsing function to be called when decoding current field
+ * @param {number} level The current nesting level
+ * @param {string=} opt_arrayVar The array variable to put the result in
  * @return {string} The JSON part of the final structure
  * @private
  */
-LabComm.Decoder.prototype.buildDecoder_ = function(name, json, fb, type, parser) {
+LabComm.Decoder.prototype.buildDecoder_ = function(name, json, fb, type, parser, level, opt_arrayVar) {
+    if(opt_arrayVar) {
+        fb.push(this.indent_(level) + opt_arrayVar + ' = ' + parser + '; //'+name+'\n');
+        return type;
+    }
+
     var varname = 'v'+this.uid_++;
     json.push('"'+name+'":'+varname);
-    fb.push('var '+varname+' = ' + parser);
+    fb.push(this.indent_(level) + 'var '+varname+' = ' + parser + '; //'+name+'\n');
     return '"'+name+'":'+'"'+type+'"'; 
 };
 
+LabComm.Decoder.prototype.indent_ = function(level) {
+    return new Array(level + 1).join('\t');
+};
+
+LabComm.Decoder.prototype.exctractArray_ = function(str) {
+    var index = str.indexOf('[');
+    if(index > 0) {
+        return {type: str.substring(0,index), dim: str.substring(index)};
+    }
+    return {type: str, dim: ''};
+}
+
+
 /**
  * Decodes a signature recursively
  * @param {string} name The name of the current field
  * @param {Array<string>} json The final json representation of the fields
  * @param {Array<string>} fb The final function body of the decoder
+ * @param {number} level The current nestling level
+ * @param {string=} opt_arrayVar The array variable to put the result in
  * @return {string} The JSON part of the sub structure
  * @throws {string} If decoding could not be performed
  * @private
  */
-LabComm.Decoder.prototype.decodeSignature_ = function(name, json, fb) {
+LabComm.Decoder.prototype.decodeSignature_ = function(name, json, fb, level, opt_arrayVar) {
     var type = this.data.getVarint();
     switch(type) {
     case LabComm.Constants.ARRAY:
-        var dim = this.data.getVarint();
-        console.log("array");
-        if(dim === 0) {
+        var arrayVariable = 'a'+this.uid_++;
+        var func = [];
+        func.push('"'+name+'":[');
+        if(!opt_arrayVar) { //only add first array to final result
+            json.push('"'+name+'":'+arrayVariable);
+        }
+
+        var indecies = this.data.getVarint();
+        if(indecies === 0) {
             throw "Array cant have 0 dimensions";
         }
-        //TODO: implement
-        throw "Array decoding not implemented";
+
+        var dims = new Array(indecies);
+        for(var i = 0; i < indecies; i++) {
+            dims[i] = this.data.getVarint();
+        }
+
+        //console.log(name + '[' + dims + ']');   
+
+        var dimStr = [];
+
+        if(indecies == 1) {
+            var dim = dims[0];
+            if(dim === 0) {
+                dimStr.push('_');
+                var arrayDimVar = 'd' + this.uid_++;
+                fb.push(this.indent_(level) + 'var ' + arrayDimVar + ' = data.getVarint();\n'); 
+                dim = arrayDimVar;
+            } else dimStr.push(dim);
+            fb.push(this.indent_(level) + 'var ' + arrayVariable + ' = new Array(' + dim + ');\n');
+            var indexVar = 'i' + this.uid_++;        
+            fb.push(this.indent_(level) + 'for(var '+indexVar+' = 0; '+indexVar+' < ' + dim + '; '+indexVar+'++) {\n')
+            var arrayType = this.decodeSignature_(name, json, fb, level+1, arrayVariable+'['+indexVar+']');
+            fb.push(this.indent_(level) + '}\n'); // array for loop
+            if(opt_arrayVar) {
+                fb.push(this.indent_(level) + opt_arrayVar+' = '+arrayVariable+';\n');
+            }
+        }
+        else {
+            var dimVars = new Array(indecies);
+            for(var i = 0; i < indecies; i++) {
+                var dim = dims[i];
+                if(dim === 0) {
+                    var arrayDimVar = 'd' + this.uid_++;
+                    fb.push(this.indent_(level) + 'var ' + arrayDimVar + ' = data.getVarint();\n'); 
+                    dim = arrayDimVar;
+                    dimStr.push('_');
+                } else dimStr.push(dim);
+                dimVars[i] = dim;
+            }
+            var endFor = [];
+            var nextVar, indexVar, prevVar, firstVar = arrayVariable;
+            for(var i = 0; i < indecies; i++) {
+                indexVar = 'i' + this.uid_++;        
+                fb.push(this.indent_(level+i) + 'var ' + arrayVariable + ' = new Array(' + dimVars[i] + ');\n');
+                fb.push(this.indent_(level+i) + 'for(var '+indexVar+' = 0; '+indexVar+' < ' + dimVars[i] + '; '+indexVar+'++) {\n')
+                
+                var nextVar = 'a' + this.uid_++;
+                endFor.unshift(
+                        this.indent_(level+i+1) + '}\n' +
+                        this.indent_(level+i+1) + arrayVariable + '[' + indexVar + '] = ' + nextVar + ';\n' + 
+                        this.indent_(level+i) + '}\n'
+                    );
+                prevVar = arrayVariable;
+                arrayVariable = nextVar;
+            }
+            var arrayType = this.decodeSignature_(name, json, fb, level+indecies, prevVar+'['+indexVar+']');
+            endFor.shift(); // remove last
+
+            fb.push(endFor.join(''));
+            if(opt_arrayVar) {
+                fb.push(this.indent_(level) + opt_arrayVar+' = '+firstVar+';\n');
+            }
+
+        }
+
+        if(opt_arrayVar) {
+            return arrayType + '['+dimStr.join(', ')+']';
+        }
+        var arrayParts = this.exctractArray_(arrayType);
+        if(arrayParts.type.charAt(0)=='{') {
+            return '"'+name+'['+dimStr.join(', ')+']'+arrayParts.dim+'":'+arrayParts.type;
+        }
+        return '"'+name+'['+dimStr.join(', ')+']'+arrayParts.dim+'":'+'"'+arrayParts.type+'"';
         break; 
     case LabComm.Constants.STRUCT:
         var func = [];
-        func.push('"'+name+'":{');
-        json.push('"'+name+'":{');
+        var subJson = [];
+        var structVar = 's' + this.uid_++;
+        if(opt_arrayVar) {
+            func.push('{');
+        }
+        else {
+            func.push('"'+name+'":{');
+        }
         var fields = this.data.getVarint();
+        //TODO: fields == 0 means a void type
         while(fields--) {
             var fn = this.data.getString();
-            func.push(this.decodeSignature_(fn, json, fb));
+            func.push(this.decodeSignature_(fn, subJson, fb, level));
             if(fields!=0) {
-                json.push(',');
+                subJson.push(',');
                 func.push(",");
             }
         }
         func.push("}");
-        json.push("}");
+
+        if(opt_arrayVar) {
+            fb.push(this.indent_(level) + opt_arrayVar + ' = {' + subJson.join('') + '};\n');
+        }
+        else {
+            fb.push(this.indent_(level) + 'var ' + structVar + ' = {' + subJson.join('') + '};\n');
+            json.push('"'+name+'":' + structVar);
+        }
         return func.join('');
     case LabComm.Constants.BOOLEAN:
-        return this.buildDecoder_(name, json, fb, "bool", "data.getBoolean()");
+        return this.buildDecoder_(name, json, fb, "bool", "data.getBoolean()", level, opt_arrayVar);
     case LabComm.Constants.BYTE:
-        return this.buildDecoder_(name, json, fb, "byte", "data.getByte()");
+        return this.buildDecoder_(name, json, fb, "byte", "data.getByte()", level, opt_arrayVar);
     case LabComm.Constants.SHORT:
-        return this.buildDecoder_(name, json, fb, "short", "data.getShort()");
+        return this.buildDecoder_(name, json, fb, "short", "data.getShort()", level, opt_arrayVar);
     case LabComm.Constants.INT:
-        return this.buildDecoder_(name, json, fb, "int", "data.getInt()");
+        return this.buildDecoder_(name, json, fb, "int", "data.getInt()", level, opt_arrayVar);
     case LabComm.Constants.LONG: 
-        return this.buildDecoder_(name, json, fb, "long", "data.getLong()");
+        return this.buildDecoder_(name, json, fb, "long", "data.getLong()", level, opt_arrayVar);
     case LabComm.Constants.FLOAT:
-        return this.buildDecoder_(name, json, fb, "float", "data.getFloat()");
+        return this.buildDecoder_(name, json, fb, "float", "data.getFloat()", level, opt_arrayVar);
     case LabComm.Constants.DOUBLE:
-        return this.buildDecoder_(name, json, fb, "double", "data.getDouble()");
+        return this.buildDecoder_(name, json, fb, "double", "data.getDouble()", level, opt_arrayVar);
     case LabComm.Constants.STRING:
-        return this.buildDecoder_(name, json, fb, "string", "data.getString()");
+        return this.buildDecoder_(name, json, fb, "string", "data.getString()", level, opt_arrayVar);
     }
     throw "Unknown type found in signature: 0x" + type.toString(16); 
 };
@@ -328,15 +441,25 @@ LabComm.Decoder.prototype.decodePackage = function(buffer) {
 
                 var json = [],
                     fb = [];
-                var struct = JSON.parse('{' + this.decodeSignature_(name, json, fb) + "}");
+                var tmp =  this.decodeSignature_(name, json, fb, 1);
+                console.log(tmp);
+                var struct = JSON.parse('{' + tmp + "}");
+                console.log(struct);
 
-                var func = fb.join(';\n\t') + ';\n\treturn {' + json.join('') + '}';
+                var func = fb.join('') + '\n\treturn {' + json.join('') + '};';
 
                 this.declarations_[index] = new LabComm.SampleDeclaration(index, name, struct, new Function('data', func));
                 break;
-            case LabComm.Constants.SAMPLE_REF:
             case LabComm.Constants.TYPE_DEF:
+                //TODO: same as sample_def
+                this.data.skip(len);
+                break;
             case LabComm.Constants.TYPE_BINDING:
+                var sampleIndex = this.data.getVarint();
+                var typeIndex = this.data.getVarint();
+                //TODO: bind?
+                break;
+            case LabComm.Constants.SAMPLE_REF:
             case LabComm.Constants.PRAGMA:
                 this.data.skip(len);
                 console.log("skipping unhandled package of size " + len);
@@ -347,8 +470,8 @@ LabComm.Decoder.prototype.decodePackage = function(buffer) {
                 
                 this.callback_(decl, sample);
 
-                break;
-        }
+                    break;
+            }
     }
 };
 
diff --git a/lib/js/tester.js b/lib/js/tester.js
new file mode 100644
index 0000000000000000000000000000000000000000..76a17b77f6c72a988d2bd40bd1e6971afc7649bc
--- /dev/null
+++ b/lib/js/tester.js
@@ -0,0 +1,43 @@
+function compareObjects(o, p) {
+    var i,
+        keysO = Object.keys(o).sort(),
+        keysP = Object.keys(p).sort();
+    if (keysO.length !== keysP.length)
+        return false;//not the same nr of keys
+    if (keysO.join('') !== keysP.join(''))
+        return false;//different keys
+    for (i=0;i<keysO.length;++i) {
+        if (o[keysO[i]] instanceof Array) {
+            if (!(p[keysO[i]] instanceof Array))
+                return false;
+            //if (compareObjects(o[keysO[i]], p[keysO[i]] === false) return false
+            //would work, too, and perhaps is a better fit, still, this is easy, too
+            if (p[keysO[i]].sort().join('') !== o[keysO[i]].sort().join(''))
+                return false;
+        }
+        else if (o[keysO[i]] instanceof Date) {
+            if (!(p[keysO[i]] instanceof Date)
+                return false;
+            if ((''+o[keysO[i]]) !== (''+p[keysO[i]]))
+                return false;
+        }
+        else if (o[keysO[i]] instanceof Function) {
+            if (!(p[keysO[i]] instanceof Function)
+                return false;
+            //ignore functions, or check them regardless?
+        }
+        else if (o[keysO[i]] instanceof Object) {
+            if (!(p[keysO[i]] instanceof Object)
+                return false;
+            if (o[keysO[i]] === o) {//self reference?
+                if (p[keysO[i]] !== p)
+                    return false;
+            }
+            else if (compareObjects(o[keysO[i]], p[keysO[i]]) === false)
+                return false;//WARNING: does not deal with circular refs other than ^^
+        }
+        if (o[keysO[i]] !== p[keysO[i]])//change !== to != for loose comparison
+            return false;//not the same value
+    }
+    return true;
+}