diff --git a/lib/js/index.html b/lib/js/index.html
index 0f15e96e5a20fb915b2465576944b7ef6d30fda3..89acdf300a83041136f4f371d4604334135d784e 100644
--- a/lib/js/index.html
+++ b/lib/js/index.html
@@ -6,22 +6,35 @@
     <script src="lc.js"></script>
   </head>
   <body>
+    <input id="url" type="text" />
+    <button id="btn">Get!</button>    
     <!-- page content -->
     <script>
-        var oReq = new XMLHttpRequest();
-        oReq.open("GET", "http://fair-2014-4.lab1.cs.lth.se:8080/logdata/clamping/experiments/bc4b3d5e-509a-40d1-81ec-1799c2ee167b/data", true);
-        oReq.responseType = "arraybuffer";
+function decodeFromUrl(url) { 
+    var oReq = new XMLHttpRequest();
+    oReq.open("GET", url, true);
+    oReq.responseType = "arraybuffer";
 
-        oReq.onload = function (oEvent) {
-          var arrayBuffer = oReq.response; // Note: not oReq.responseText
-          if (arrayBuffer) {
-              var buff = new LabComm.Buffer(new DataView(arrayBuffer));
-              console.log(buff);
-            new LabComm.Parser(buff);
-          }
-        };
+    oReq.onload = function (oEvent) {
+        var arrayBuffer = oReq.response; 
+        if (arrayBuffer) {
+            var buff = new LabComm.Buffer(new DataView(arrayBuffer));
+            window.decoder = new LabComm.Decoder(function(decl, data) {
+                console.log(data);
+            });
+            window.decoder.decodePackage(buff);
+        }
+    };
+
+    oReq.send(null);
+}
+
+var urlInp = document.getElementById('url');
+var btn = document.getElementById('btn');
+btn.onclick = function() {
+    decodeFromUrl(urlInp.value);
+};
 
-        oReq.send(null);
     </script>
   </body>
 </html>
diff --git a/lib/js/lc.js b/lib/js/lc.js
index 8a411a2274d32118c7f511aa1ebbbd18e8e045b6..ceff9ca5e708e947c1e3d6545c35f8e4ea8b24d2 100644
--- a/lib/js/lc.js
+++ b/lib/js/lc.js
@@ -2,6 +2,12 @@
 
 var LabComm = LabComm || {};
 
+/** 
+ * The maximum "safe" integer that can be stroed in a double
+ * @define {number} 
+ */
+var MAX_INT = 0x1fffffffffffff;
+
 /**
  * Constants used during parsing
  * @enum {number}
@@ -32,8 +38,49 @@ LabComm.Constants = {
  * @param {number=} offset An initial offset, defaults to 0
  */
 LabComm.Buffer = function (dataView, offset) {
-    this.offset = offset || 0;
-    this.data = dataView;
+    /**
+     * The current position in the buffer
+     * @type {number}
+     * @private
+     */
+    this.offset_ = offset || 0;
+
+    /**
+     * The underlying dataview
+     * @type {DataView}
+     * @private
+     */
+    this.data_ = dataView;
+
+    /**
+     * The original offset, used to rewind
+     * @type {number}
+     * @private
+     */
+    this.originalOffset_ = this.offset_; 
+};
+
+/**
+ * Check if there is more data that can be red
+ * @return {boolean} True if there is more data left
+ */
+LabComm.Buffer.prototype.hasRemaning = function() {
+    return this.offset_ < this.data_.byteLength;
+};
+
+/**
+ * Returns the remaning number of bytes
+ * @return {number} The number of bytes left
+ */
+LabComm.Buffer.prototype.remaning = function() {
+    return this.data_.byteLength - this.offset_;
+};
+
+/**
+ * Sets the position to the beginning of the buffer
+ */
+LabComm.Buffer.prototype.rewind = function() {
+    this.offset_ = this.originalOffset_;
 };
 
 /**
@@ -43,11 +90,11 @@ LabComm.Buffer = function (dataView, offset) {
 LabComm.Buffer.prototype.getVarint = function() {
     var nextByte, result = 0, bytesRead = 0;
     do {
-        nextByte = this.data.getUint8(this.offset+bytesRead);
+        nextByte = this.data_.getUint8(this.offset_+bytesRead);
         result += (nextByte & 0x7F) << (7 * bytesRead);
         bytesRead++;
     } while (nextByte >= 0x80)
-    this.offset += bytesRead;
+    this.offset_ += bytesRead;
     return result;
 };
 
@@ -59,10 +106,10 @@ LabComm.Buffer.prototype.getString = function() {
     var len = this.getVarint();
     var chars = new Uint8Array(len);
     for(var i = 0; i < len; i++) {
-        chars[i] = this.data.getUint8(this.offset + i);
+        chars[i] = this.data_.getUint8(this.offset_ + i);
     }
     var str = String.fromCharCode.apply(null, chars);
-    this.offset += len;
+    this.offset_ += len;
     return str;
 };
 
@@ -71,7 +118,7 @@ LabComm.Buffer.prototype.getString = function() {
  * @return {Boolean} A boolean
  */
 LabComm.Buffer.prototype.getBoolean = function() {
-    return new Boolean(this.data.getUint8(this.offset++));
+    return new Boolean(this.data_.getUint8(this.offset_++));
 };
 
 /**
@@ -79,7 +126,7 @@ LabComm.Buffer.prototype.getBoolean = function() {
  * @return {number} A byte
  */
 LabComm.Buffer.prototype.getByte = function() {
-    return this.data.getUint8(this.offset++);
+    return this.data_.getUint8(this.offset_++);
 };
 
 /**
@@ -87,8 +134,8 @@ LabComm.Buffer.prototype.getByte = function() {
  * @return {number} A short
  */
 LabComm.Buffer.prototype.getShort = function() {
-    var s = this.data.getInt16(this.offset);
-    this.offset += 2;
+    var s = this.data_.getInt16(this.offset_);
+    this.offset_ += 2;
     return s;
 };
 
@@ -97,8 +144,8 @@ LabComm.Buffer.prototype.getShort = function() {
  * @return {number} An integer
  */ 
 LabComm.Buffer.prototype.getInt = function() {
-    var s = this.data.getInt32(this.offset);
-    this.offset += 4;
+    var s = this.data_.getInt32(this.offset_);
+    this.offset_ += 4;
     return s;
 };
 
@@ -109,10 +156,15 @@ LabComm.Buffer.prototype.getInt = function() {
  * @return {number} A long
  */
 LabComm.Buffer.prototype.getLong = function() {
-    var low = this.data.getInt32(this.offset + 4);
-    var n = this.data.getInt32(this.offset) * 0x100000000 + low;
+    var low = this.data_.getInt32(this.offset_ + 4);
+    var n = this.data_.getInt32(this.offset_) * 0x100000000 + low;
     if (low < 0) n += 0x100000000;
-    this.offset += 8;
+    this.offset_ += 8;
+
+    if(Math.abs(n) > MAX_INT) {
+        return n < 0 ? -Infinity : Infinity;
+    }
+
     return n;
 };
 
@@ -121,8 +173,8 @@ LabComm.Buffer.prototype.getLong = function() {
  * @return {number} A float
  */
 LabComm.Buffer.prototype.getFloat = function() {
-    var s = this.data.getFloat32(this.offset);
-    this.offset += 4;
+    var s = this.data_.getFloat32(this.offset_);
+    this.offset_ += 4;
     return s;
 };
 
@@ -131,8 +183,8 @@ LabComm.Buffer.prototype.getFloat = function() {
  * @return {number} A double
  */
 LabComm.Buffer.prototype.getDouble = function() {
-    var s = this.data.getFloat64(this.offset);
-    this.offset += 8;
+    var s = this.data_.getFloat64(this.offset_);
+    this.offset_ += 8;
     return s;
 };
 
@@ -141,106 +193,144 @@ 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_ += len;
 };
 
 
 
 
-
-
-
 /**
- * A 
+ * A parser that cad decode LabComm binary data
  * @constructor
- * @param {LabComm.Buffer} A buffer to parse from
+ * @param {function(LabComm.SampleDeclaration, Object)=} callback A callback that will get all the decoded samples
  */
-LabComm.Parser = function(buffer) {
-    this.data = buffer;
-
+LabComm.Decoder = function(callback) {
+    /**
+     * The sample declarations that has been registred so far
+     * @type {Object<number, LabComm.SampleDeclaration>}
+     * @private
+     */
+    this.declarations_ = {};
+
+    /**
+     * The callback that will recieve all samples and declarations
+     * @type {function(LabComm.SampleDeclaration, Object)}
+     * @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;
 
-    var _uid = 1;
-    function uid() {return this._uid++};
+/**
+ * Builds a part of the decoder function
+ * @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 {string} type The string representation of the type
+ * @param {string} parser The parsing function to be called when decoding current field
+ * @return {string} The JSON part of the final structure
+ * @private
+ */
+LabComm.Decoder.prototype.buildDecoder_ = function(name, json, fb, type, parser) {
+    var varname = 'v'+this.uid_++;
+    json.push('"'+name+'":'+varname);
+    fb.push('var '+varname+' = ' + parser);
+    return '"'+name+'":'+'"'+type+'"'; 
+};
 
-    function buildParser(name, json, fb, type, parser) {
-        var varname = 'v'+_uid++;
-        json.push('"'+name+'":'+varname);
-        fb.push('var '+varname+' = ' + parser);
-        return '"'+name+'":'+'"'+type+'"'; 
-    }
-    this.sig = function(name, json, fb) {
-        var type = this.data.getVarint();
-        switch(type) {
-        case LabComm.Constants.ARRAY:
-            console.log("array");
-            //TODO: implement
-            break; 
-        case LabComm.Constants.STRUCT:
-            var func = [];
-            func.push('"'+name+'":{');
-            json.push('"'+name+'":{');
-            var fields = this.data.getVarint();
-            while(fields--) {
-                var fn = this.data.getString();
-                func.push(this.sig(fn, json, fb));
-                if(fields!=0) {
-                    json.push(',');
-                    func.push(",");
-                }
+/**
+ * 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
+ * @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) {
+    var type = this.data.getVarint();
+    switch(type) {
+    case LabComm.Constants.ARRAY:
+        var dim = this.data.getVarint();
+        if(dim === 0) {
+            throw "Array cant have 0 dimensions";
+        }
+        console.log("array");
+        //TODO: implement
+        throw "Array decoding not implemented";
+        break; 
+    case LabComm.Constants.STRUCT:
+        var func = [];
+        func.push('"'+name+'":{');
+        json.push('"'+name+'":{');
+        var fields = this.data.getVarint();
+        while(fields--) {
+            var fn = this.data.getString();
+            func.push(this.decodeSignature_(fn, json, fb));
+            if(fields!=0) {
+                json.push(',');
+                func.push(",");
             }
-            func.push("}");
-            json.push("}");
-            return func.join('');
-        case LabComm.Constants.BOOLEAN:
-            return buildParser(name, json, fb, "bool", "data.getBoolean()");
-        case LabComm.Constants.BYTE:
-            return buildParser(name, json, fb, "byte", "data.getByte()");
-        case LabComm.Constants.SHORT:
-            return buildParser(name, json, fb, "short", "data.getShort()");
-        case LabComm.Constants.INT:
-            return buildParser(name, json, fb, "int", "data.getInt()");
-        case LabComm.Constants.LONG: 
-            return buildParser(name, json, fb, "long", "data.getLong()");
-        case LabComm.Constants.FLOAT:
-            return buildParser(name, json, fb, "float", "data.getFloat()");
-        case LabComm.Constants.DOUBLE:
-            return buildParser(name, json, fb, "double", "data.getDouble()");
-        case LabComm.Constants.STRING:
-            return buildParser(name, json, fb, "string", "data.getString()");
         }
+        func.push("}");
+        json.push("}");
+        return func.join('');
+    case LabComm.Constants.BOOLEAN:
+        return this.buildDecoder_(name, json, fb, "bool", "data.getBoolean()");
+    case LabComm.Constants.BYTE:
+        return this.buildDecoder_(name, json, fb, "byte", "data.getByte()");
+    case LabComm.Constants.SHORT:
+        return this.buildDecoder_(name, json, fb, "short", "data.getShort()");
+    case LabComm.Constants.INT:
+        return this.buildDecoder_(name, json, fb, "int", "data.getInt()");
+    case LabComm.Constants.LONG: 
+        return this.buildDecoder_(name, json, fb, "long", "data.getLong()");
+    case LabComm.Constants.FLOAT:
+        return this.buildDecoder_(name, json, fb, "float", "data.getFloat()");
+    case LabComm.Constants.DOUBLE:
+        return this.buildDecoder_(name, json, fb, "double", "data.getDouble()");
+    case LabComm.Constants.STRING:
+        return this.buildDecoder_(name, json, fb, "string", "data.getString()");
     }
+    throw "Unknown type found in signature: 0x" + tag.toString(16); 
+};
 
-    this._defs = {};
-
-    for(var i = 1; i < 6; i ++) {
+/**
+ * Decodes a buffer to Samples
+ * @param {LabComm.Buffer} buffer The buffer to decode
+ * @throws {string} If error during decoding
+ */
+LabComm.Decoder.prototype.decodePackage = function(buffer) {
+    this.data = buffer;
+    while(this.data.hasRemaning()) {
         var tag = this.data.getVarint();
         var len = this.data.getVarint();
-        console.log("tag: 0x" + tag.toString(16));
-        console.log("len: 0x" + len.toString(16));
 
         switch(tag) {
             case LabComm.Constants.VERSION: 
                 var version = this.data.getString();
-                console.log("LabComm version package: " + version);
+                if(version !== "LabComm2014") {
+                    throw "Unsupported LabComm version: " + version;
+                }
                 break;
             case LabComm.Constants.SAMPLE_DEF:
                 var index = this.data.getVarint();
                 var name = this.data.getString();
                 var siglen = this.data.getVarint();
 
-                console.log("sample def: 0x" + index.toString(16) + ":" + name + ", size: 0x" + siglen.toString(16));
                 var json = [],
                     fb = [];
-                var struct = JSON.parse('{' + this.sig(name, json, fb) + "}");
+                var struct = JSON.parse('{' + this.decodeSignature_(name, json, fb) + "}");
 
                 var func = fb.join(';\n\t') + ';\n\treturn {' + json.join('') + '}';
-                this._defs[index] = {
-                    index: index,
-                    name: name,
-                    struct: struct,
-                    decoder: new Function('data', func)
-                };
+
+                this.declarations_[index] = new LabComm.SampleDeclaration(index, name, struct, new Function('data', func));
                 break;
             case LabComm.Constants.SAMPLE_REF:
             case LabComm.Constants.TYPE_DEF:
@@ -250,17 +340,56 @@ LabComm.Parser = function(buffer) {
                 console.log("skipping unhandled package of size " + len);
                 break;
             default: 
-                var s = this._defs[tag];
-
-                var decoder = s.decoder;
-                var sample = decoder(this.data);
-                console.log("sample name: " + s.name);
-                console.log(decoder);
+                var decl = this.declarations_[tag];
+                var sample = decl.decode(this.data);
                 
-                console.log(sample);
+                this.callback_(decl, sample);
 
                 break;
         }
     }
-}
+};
+
+/**
+ * A Sample declaration
+ * @constructor
+ * @param {number} index The samles tag-index
+ * @param {string} name The name of the sample
+ * @param {*} struct A JSON representation of the sample
+ * @param {function(LabComm.Buffer) : Object} func The decoder function
+ */
+LabComm.SampleDeclaration = function(index, name, struct, func) {
+    /**
+     * The tag index
+     * @type{number}
+     */
+    this.index = index;
+
+    /**
+     * The name of the sample
+     * @type {string}
+     */
+    this.name = name;
+
+    /**
+     * The JSON representation of the sample, can be used to re-create the .lc file
+     * @type {*}
+     */
+    this.struct = struct;
+
+    /**
+     * The decoder that turns a buffer into a JSON sample
+     * @type {function(LabComm.Buffer) : Object}
+     * @private
+     */
+    this.decoder_ = func;
+};
 
+/**
+ * Decodes a complete sample and returns a JSON obejct with the data
+ * @param {LabComm.Buffer} data The buffer that contains the sample
+ * @return {Object} The JSON object with the data
+ */
+LabComm.SampleDeclaration.prototype.decode = function(data) {
+    return this.decoder_(data);
+};