<commit_before>var chan = (function() {
    'use strict';
    var protocol_error = function(name, o) {
        var type = typeof o;
        if ('object' == type) {
            if (o){
                if(o.constructor === Array) {
                    type = "array";
                } else {
                    type = Object.prototype.toString.call(o);
                }
            } else {
                type = 'null';
            }
        }
        return new Error(["No protocol method ", name, " defined for type ", type, ": ", o].join(""));
    };
    var protocols = {
        MMC: {
            cleanup: function(o) {
                if (o && o.csp$channel$MMC$cleanup) {
                    return o.csp$channel$MMC$cleanup(o);
                }
                throw protocol_error('csp.channel.MMC/cleanup', o);
            }
        },
        ReadPort: {
            take: function(o, handler) {
                if (o && o.csp$channel$ReadPort$take) {
                    return o.csp$channel$ReadPort$take(o, handler);
                }
                throw protocol_error('csp.channel.ReadPort/take', o);
            }
        },
        WritePort: {
            put: function(o, val, handler) {
                if (o && o.csp$channel$WritePort$put) {
                    return o.csp$channel$WritePort$put(o, val, handler);
                }
                throw protocol_error('csp.channel.WritePort/put', o);
            }
        },
        Channel: {
            close: function(o) {
                if (o && o.csp$channel$Channel$close) {
                    return o.csp$channel$Channel$close(o);
                }
                throw protocol_error('csp.channel.Channel/close', o);
            },
            closed: function(o) {
                if (o && o.csp$channel$Channel$closed) {
                    return o.csp$channel$Channel$closed(o);
                }
                throw protocol_error('csp.channel.Channel/closed', o);
            }
        },
        Buffer: {
            full: function(o) {
                if (o && o.csp$channel$Buffer$full) {
                    return o.csp$channel$Buffer$full(o);
                }
                throw protocol_error('csp.channel.Buffer/full', o);
            },
            remove: function(o) {
                if (o && o.csp$channel$Buffer$remove) {
                    return o.csp$channel$Buffer$remove(o);
                }
                throw protocol_error('csp.channel.Buffer/remove', o);
            },
            add: function(o, item) {
                if (o && o.csp$channel$Buffer$add) {
                    return o.csp$channel$Buffer$add(o, item);
                }
                throw protocol_error('csp.channel.Buffer/add', o);
            }
        },
        Handler: {
            active: function(o) {
                if (o && o.csp$channel$Handler$active) {
                    return o.csp$channel$Handler$active(o);
                }
                throw protocol_error('csp.channel.Handler/active', o);
            },
            commit: function(o) {
                if (o && o.csp$channel$Handler$commit) {
                    return o.csp$channel$Handler$commit(o);
                }
                throw protocol_error('csp.channel.Handler/commit', o);
            }
        },
        Core: {
            deref: function(o) {
                if (o && o.csp$Core$deref) {
                    return o.csp$Core$deref(o);
                }
                throw protocol_error('csp.Core/deref', o);
            },
            count: function(o) {
                if (o && o.csp$Core$count) {
                    return o.csp$Core$count(o);
                }
                throw protocol_error('csp.Core/count', o);
            }
        },
    };

    var impl = (function(p){
        var i,j, impl = {};
        for(i in p) {
            if (p.hasOwnProperty(i)) {
                for (j in p[i]) {
                    if (p[i].hasOwnProperty(j)) {
                        impl[j] = p[i][j];
                    }
                }
            }
        }
        return impl;
    })(protocols);

    var box = function(val) {
        return {
            csp$Core$deref: function(o) {
                return val;
            }
        };
    };
    var dispatch = (function() {
        return {
            run: function(f) {
                setTimeout(f, 0);
            }
        };
    })();
    var Channel = (function(impl, box, dispatch) {
        var Channel = function(takes, puts, buffer, closed) {
            this.takes = takes;
            this.puts = puts;
            this.buffer = buffer;
            this.closed = {csp$Core$deref: function() { return closed;}};
        };

        var p = Channel.prototype;

        p.csp$channel$MMC$cleanup = function(o) {
            var i, item, tlen = o.takes.length, plen = o.puts.length;
            for(i = 0; i < plen; i++) {
                item = o.puts[i][0];
                if (! impl.active(item)) {
                    o.puts.splice(i, 1);
                }
            }
            for(i = 0; i < tlen; i++) {
                item = o.takes[i];
                if (! impl.active(item)) {
                    o.takes.splice(i, 1);
                }
            }
            return null;
        };

        p.csp$channel$WritePort$put = function(o, val, handler) {
            if (val === null) {
                throw (new Error("Cant put null in a channel"));
            }
            impl.cleanup(o);
            if (impl.closed(o)) {
                return box(null);
            } else {
                var take_cb, put_cb, taker, i, tlen = o.takes.length;
                for (i = 0; i < tlen; i++) {
                    taker = o.takes[i];
                    if (impl.active(taker) && impl.active(handler)) {
                        o.takes.splice(i, 1);
                        take_cb = impl.commit(taker);
                        put_cb = impl.commit(handler);
                        break;
                    }
                }
                if (take_cb && put_cb) {
                    dispatch.run(function() { return take_cb(val);});
                    return box(null);
                } else {
                    if (o.buffer && (! impl.full(o.buffer))) {
                        if (impl.active(handler) && impl.commit(handler)) {
                            impl.add(o.buffer, val);
                            return box(null);
                        }
                        return null;
                    } else {
                        o.puts.unshift([handler, val]);
                        return null;
                    }
                }
            }
            return null;
        };

        p.csp$channel$ReadPort$take = function(o, handler) {
            impl.cleanup(o);
            if (o.buffer && (impl.count(o.buffer) > 0)) {
                if (impl.active(handler) && impl.commit(handler)) {
                    return box(impl.remove(o.buffer));
                }
                return null;
            } else {
                var take_cb, put_cb, val, putter, i, plen = o.puts.length;
                for (i = 0; i < plen; i++) {
                    putter = o.puts[i][0];
                    if (impl.active(putter) && impl.active(handler)) {
                        o.takes.splice(i, 1);
                        take_cb = impl.commit(handler);
                        put_cb = impl.commit(putter);
                        val = o.puts[i][1];
                        break;
                    }
                }

                if (take_cb && put_cb) {
                    dispatch.run(put_cb);
                    return box(val);
                } else {
                    if (impl.closed(o)) {
                        if (impl.active(handler) && impl.commit(handler)) {
                            return box(null);
                        }
                        return null;
                    } else {
                        o.takes.unshift(handler);
                        return null;
                    }
                }
            }
            return null;
        };

        p.csp$channel$Channel$close = function(o) {
            impl.cleanup(o);
            if (impl.closed(o)) {
                return null;
            } else {
                o.closed = {csp$Core$deref: function() { return true;}};
                var taker, take_cb, i, tlen = o.takes.length;
                for (i = 0; i < tlen; i++) {
                    taker = o.takes[i];
                    take_cb = (impl.active(taker) && impl.commit(taker));
                    (function(take_cb){
                        if (take_cb) {
                            dispatch.run(function() { return take_cb(null); });
                        }
                    })(take_cb);
                }
                return null;
            }
            return null;
        };

        p.csp$channel$Channel$closed = function(o) {
            return impl.deref(o.closed) === true;
        };
        return Channel;
    })(impl, box, dispatch);

    var Buffers = (function(){
        var FixedBuffer = function(buffer, n) {
            this.buffer = buffer;
            this.n = n;
        };
        var fb = FixedBuffer.prototype;
        fb.csp$channel$Buffer$full = function(b) {
            return (b.buffer.length === b.n);
        };
        fb.csp$channel$Buffer$remove = function(b) {
            return b.buffer.pop();
        };
        fb.csp$channel$Buffer$add = function(b, item) {
            if (impl.full(b)) {
                throw (new Error("Can't add to a full buffer"));
            }
            return b.buffer.unshift(item);
        };
        fb.csp$Core$count = function(o) {
            return o.buffer.length;
        };
        var DroppingBuffer = function(buffer, n) {
            this.buffer = buffer;
            this.n = n;
        };
        var db = DroppingBuffer.prototype;
        db.csp$channel$Buffer$full = function(b) {
            return false;
        };
        db.csp$channel$Buffer$remove = function(b) {
            return b.buffer.pop();
        };
        db.csp$channel$Buffer$add = function(b, item) {
            if (b.buffer.length !== b.n) {
                return b.buffer.unshift(item);
            }
            return null;
        };
        db.csp$Core$count = function(o) {
            return o.buffer.length;
        };
        var SlidingBuffer = function(buffer, n) {
            this.buffer = buffer;
            this.n = n;
        };
        var sb = SlidingBuffer.prototype;
        sb.csp$channel$Buffer$full = function(b) {
            return false;
        };
        sb.csp$channel$Buffer$remove = function(b) {
            return b.buffer.pop();
        };
        sb.csp$channel$Buffer$add = function(b, item) {
            if (b.buffer.length === b.n) {
                impl.remove(b);
            }
            return b.buffer.unshift(item);
        };
        sb.csp$Core$count = function(o) {
            return o.buffer.length;
        };
        return {
            Fixed: FixedBuffer,
            Dropping: DroppingBuffer,
            Sliding: SlidingBuffer
        };
    })(impl);

    var util = (function(){
        return {
            handler: function(f) {
                return {
                    csp$channel$Handler$active: function(o) { return true;},
                    csp$channel$Handler$commit: function(o) { return f;}
                };
            }
        };
    })();

    var show = (function(impl, handler, run, Buffers, box){
        var nop = function() {return null; };

        var random_array = function(n) {
            var i, j, a = [];
            for(i = 0; i < n; i++) {
                a.push(0);
            }
            for(i = 1; i < n; i++) {
                j = Math.floor(Math.random() * i);
                a[i] = a[j];
                a[j] = i;
            }
            return a;
        };

        var alt_flag = function() {
            var flag = true;
            return {
                csp$channel$Handler$active: function(o) { return flag;},
                csp$channel$Handler$commit: function(o) {
                    flag = null;
                    return true;
                }
            };
        };
        var alt_handler = function(flag, cb) {
            return {
                csp$channel$Handler$active: function(o) { return impl.active(flag);},
                csp$channel$Handler$commit: function(o) {
                    impl.commit(flag);
                    return cb;
                }
            };
        };
        return {
            chan: function(buffer) {
                return new Channel([], [], buffer, null);
            },
            take: function(port, fn1, on_caller) {
                on_caller = on_caller || true;
                var ret = impl.take(port, handler(fn1));
                if (ret) {
                    var val = impl.deref(ret);
                    if (on_caller) {
                        fn1(val);
                    } else {
                        run(function() { return fn1(val);});
                    }
                }
                return null;
            },
            put: function(port, val, fn0, on_caller) {
                fn0 = fn0 || nop;
                on_caller = on_caller || true;
                var ret = impl.put(port, val, handler(fn0));
                if (ret && (fn0  !== nop)) {
                    if (on_caller) {
                        fn0();
                    } else {
                        run(fn0);
                    }
                }
                return null;
            },
            close: function(port) {
                return impl.close(port);
            },
            closed: function(port) {
                return impl.closed(port);
            },
            alts: function(ports, fret, options) {
                options = options || {};
                var flag = alt_flag(),
                    n = ports.length,
                    idxs = random_array(n),
                    priority = (options.hasOwnProperty('priority')),
                    ret, i, idx, wport, port, val, h, vbox;
                for(i = 0; i < n; i++) {
                    idx = priority ? i : idxs[i];
                    port = ports[idx];
                    wport = (port.constructor === Array) ? port[0] : null;
                    h = (function(wport, port){
                        if (wport) {
                            return alt_handler(flag, function() { return fret(null, wport);});
                        }
                        return alt_handler(flag, function(v) { return fret(v, port);});
                    })(wport, port);
                    if (wport) {
                        vbox = impl.put(wport, port[1], h);
                    } else {
                        vbox = impl.take(port, h);
                    }
                    if (vbox) {
                        ret = box([impl.deref(vbox), (wport ? wport : port)]);
                    }
                }
                if (ret) {
                    return ret;
                }
                if (options.hasOwnProperty('default')) {
                    if (impl.active(flag) && impl.commit(flag)) {
                        box([options['default'], 'default']);
                    }
                }
                return null;
            },
            fixed_buffer: function(n) {
                return new Buffers.Fixed([], n);
            },
            dropping_buffer : function(n) {
                return new Buffers.Dropping([], n);
            },
            sliding_buffer: function(n) {
                return new Buffers.Sliding([], n);
            }
        };
    })(impl, util.handler, dispatch.run, Buffers, box);
    return {
        "impl": {
            "cleanup": impl.cleanup,
            "take": impl.take,
            "put": impl.put,
            "close": impl.close,
            "closed": impl.closed,
            "full": impl.full,
            "remove": impl.remove,
            "add": impl.add,
            "active": impl.active,
            "commit": impl.commit
        },
        "types": {
            "Channel": Channel,
            "FixedBuffer": Buffers.Fixed,
            "DroppingBuffer": Buffers.Dropping,
            "SlidingBuffer": Buffers.Sliding
        },
        "util": {
            "handler": util.handler
        },
        "chan": show.chan,
        "take": show.take,
        "put": show.put,
        "close": show.close,
        "closed": show.closed,
        "alts": show.alts,
        "fixed_buffer": show.fixed_buffer,
        "dropping_buffer": show.dropping_buffer,
        "sliding_buffer": show.sliding_buffer
    };
})();
<commit_msg>Added the deref protocol so that the front end users can get the reference value<commit_after>var chan = (function() {
    'use strict';
    var protocol_error = function(name, o) {
        var type = typeof o;
        if ('object' == type) {
            if (o){
                if(o.constructor === Array) {
                    type = "array";
                } else {
                    type = Object.prototype.toString.call(o);
                }
            } else {
                type = 'null';
            }
        }
        return new Error(["No protocol method ", name, " defined for type ", type, ": ", o].join(""));
    };
    var protocols = {
        MMC: {
            cleanup: function(o) {
                if (o && o.csp$channel$MMC$cleanup) {
                    return o.csp$channel$MMC$cleanup(o);
                }
                throw protocol_error('csp.channel.MMC/cleanup', o);
            }
        },
        ReadPort: {
            take: function(o, handler) {
                if (o && o.csp$channel$ReadPort$take) {
                    return o.csp$channel$ReadPort$take(o, handler);
                }
                throw protocol_error('csp.channel.ReadPort/take', o);
            }
        },
        WritePort: {
            put: function(o, val, handler) {
                if (o && o.csp$channel$WritePort$put) {
                    return o.csp$channel$WritePort$put(o, val, handler);
                }
                throw protocol_error('csp.channel.WritePort/put', o);
            }
        },
        Channel: {
            close: function(o) {
                if (o && o.csp$channel$Channel$close) {
                    return o.csp$channel$Channel$close(o);
                }
                throw protocol_error('csp.channel.Channel/close', o);
            },
            closed: function(o) {
                if (o && o.csp$channel$Channel$closed) {
                    return o.csp$channel$Channel$closed(o);
                }
                throw protocol_error('csp.channel.Channel/closed', o);
            }
        },
        Buffer: {
            full: function(o) {
                if (o && o.csp$channel$Buffer$full) {
                    return o.csp$channel$Buffer$full(o);
                }
                throw protocol_error('csp.channel.Buffer/full', o);
            },
            remove: function(o) {
                if (o && o.csp$channel$Buffer$remove) {
                    return o.csp$channel$Buffer$remove(o);
                }
                throw protocol_error('csp.channel.Buffer/remove', o);
            },
            add: function(o, item) {
                if (o && o.csp$channel$Buffer$add) {
                    return o.csp$channel$Buffer$add(o, item);
                }
                throw protocol_error('csp.channel.Buffer/add', o);
            }
        },
        Handler: {
            active: function(o) {
                if (o && o.csp$channel$Handler$active) {
                    return o.csp$channel$Handler$active(o);
                }
                throw protocol_error('csp.channel.Handler/active', o);
            },
            commit: function(o) {
                if (o && o.csp$channel$Handler$commit) {
                    return o.csp$channel$Handler$commit(o);
                }
                throw protocol_error('csp.channel.Handler/commit', o);
            }
        },
        Core: {
            deref: function(o) {
                if (o && o.csp$Core$deref) {
                    return o.csp$Core$deref(o);
                }
                throw protocol_error('csp.Core/deref', o);
            },
            count: function(o) {
                if (o && o.csp$Core$count) {
                    return o.csp$Core$count(o);
                }
                throw protocol_error('csp.Core/count', o);
            }
        },
    };

    var impl = (function(p){
        var i,j, impl = {};
        for(i in p) {
            if (p.hasOwnProperty(i)) {
                for (j in p[i]) {
                    if (p[i].hasOwnProperty(j)) {
                        impl[j] = p[i][j];
                    }
                }
            }
        }
        return impl;
    })(protocols);

    var box = function(val) {
        return {
            csp$Core$deref: function(o) {
                return val;
            }
        };
    };
    var dispatch = (function() {
        return {
            run: function(f) {
                setTimeout(f, 0);
            }
        };
    })();
    var Channel = (function(impl, box, dispatch) {
        var Channel = function(takes, puts, buffer, closed) {
            this.takes = takes;
            this.puts = puts;
            this.buffer = buffer;
            this.closed = {csp$Core$deref: function() { return closed;}};
        };

        var p = Channel.prototype;

        p.csp$channel$MMC$cleanup = function(o) {
            var i, item, tlen = o.takes.length, plen = o.puts.length;
            for(i = 0; i < plen; i++) {
                item = o.puts[i][0];
                if (! impl.active(item)) {
                    o.puts.splice(i, 1);
                }
            }
            for(i = 0; i < tlen; i++) {
                item = o.takes[i];
                if (! impl.active(item)) {
                    o.takes.splice(i, 1);
                }
            }
            return null;
        };

        p.csp$channel$WritePort$put = function(o, val, handler) {
            if (val === null) {
                throw (new Error("Cant put null in a channel"));
            }
            impl.cleanup(o);
            if (impl.closed(o)) {
                return box(null);
            } else {
                var take_cb, put_cb, taker, i, tlen = o.takes.length;
                for (i = 0; i < tlen; i++) {
                    taker = o.takes[i];
                    if (impl.active(taker) && impl.active(handler)) {
                        o.takes.splice(i, 1);
                        take_cb = impl.commit(taker);
                        put_cb = impl.commit(handler);
                        break;
                    }
                }
                if (take_cb && put_cb) {
                    dispatch.run(function() { return take_cb(val);});
                    return box(null);
                } else {
                    if (o.buffer && (! impl.full(o.buffer))) {
                        if (impl.active(handler) && impl.commit(handler)) {
                            impl.add(o.buffer, val);
                            return box(null);
                        }
                        return null;
                    } else {
                        o.puts.unshift([handler, val]);
                        return null;
                    }
                }
            }
            return null;
        };

        p.csp$channel$ReadPort$take = function(o, handler) {
            impl.cleanup(o);
            if (o.buffer && (impl.count(o.buffer) > 0)) {
                if (impl.active(handler) && impl.commit(handler)) {
                    return box(impl.remove(o.buffer));
                }
                return null;
            } else {
                var take_cb, put_cb, val, putter, i, plen = o.puts.length;
                for (i = 0; i < plen; i++) {
                    putter = o.puts[i][0];
                    if (impl.active(putter) && impl.active(handler)) {
                        o.takes.splice(i, 1);
                        take_cb = impl.commit(handler);
                        put_cb = impl.commit(putter);
                        val = o.puts[i][1];
                        break;
                    }
                }

                if (take_cb && put_cb) {
                    dispatch.run(put_cb);
                    return box(val);
                } else {
                    if (impl.closed(o)) {
                        if (impl.active(handler) && impl.commit(handler)) {
                            return box(null);
                        }
                        return null;
                    } else {
                        o.takes.unshift(handler);
                        return null;
                    }
                }
            }
            return null;
        };

        p.csp$channel$Channel$close = function(o) {
            impl.cleanup(o);
            if (impl.closed(o)) {
                return null;
            } else {
                o.closed = {csp$Core$deref: function() { return true;}};
                var taker, take_cb, i, tlen = o.takes.length;
                for (i = 0; i < tlen; i++) {
                    taker = o.takes[i];
                    take_cb = (impl.active(taker) && impl.commit(taker));
                    (function(take_cb){
                        if (take_cb) {
                            dispatch.run(function() { return take_cb(null); });
                        }
                    })(take_cb);
                }
                return null;
            }
            return null;
        };

        p.csp$channel$Channel$closed = function(o) {
            return impl.deref(o.closed) === true;
        };
        return Channel;
    })(impl, box, dispatch);

    var Buffers = (function(){
        var FixedBuffer = function(buffer, n) {
            this.buffer = buffer;
            this.n = n;
        };
        var fb = FixedBuffer.prototype;
        fb.csp$channel$Buffer$full = function(b) {
            return (b.buffer.length === b.n);
        };
        fb.csp$channel$Buffer$remove = function(b) {
            return b.buffer.pop();
        };
        fb.csp$channel$Buffer$add = function(b, item) {
            if (impl.full(b)) {
                throw (new Error("Can't add to a full buffer"));
            }
            return b.buffer.unshift(item);
        };
        fb.csp$Core$count = function(o) {
            return o.buffer.length;
        };
        var DroppingBuffer = function(buffer, n) {
            this.buffer = buffer;
            this.n = n;
        };
        var db = DroppingBuffer.prototype;
        db.csp$channel$Buffer$full = function(b) {
            return false;
        };
        db.csp$channel$Buffer$remove = function(b) {
            return b.buffer.pop();
        };
        db.csp$channel$Buffer$add = function(b, item) {
            if (b.buffer.length !== b.n) {
                return b.buffer.unshift(item);
            }
            return null;
        };
        db.csp$Core$count = function(o) {
            return o.buffer.length;
        };
        var SlidingBuffer = function(buffer, n) {
            this.buffer = buffer;
            this.n = n;
        };
        var sb = SlidingBuffer.prototype;
        sb.csp$channel$Buffer$full = function(b) {
            return false;
        };
        sb.csp$channel$Buffer$remove = function(b) {
            return b.buffer.pop();
        };
        sb.csp$channel$Buffer$add = function(b, item) {
            if (b.buffer.length === b.n) {
                impl.remove(b);
            }
            return b.buffer.unshift(item);
        };
        sb.csp$Core$count = function(o) {
            return o.buffer.length;
        };
        return {
            Fixed: FixedBuffer,
            Dropping: DroppingBuffer,
            Sliding: SlidingBuffer
        };
    })(impl);

    var util = (function(){
        return {
            handler: function(f) {
                return {
                    csp$channel$Handler$active: function(o) { return true;},
                    csp$channel$Handler$commit: function(o) { return f;}
                };
            }
        };
    })();

    var show = (function(impl, handler, run, Buffers, box){
        var nop = function() {return null; };

        var random_array = function(n) {
            var i, j, a = [];
            for(i = 0; i < n; i++) {
                a.push(0);
            }
            for(i = 1; i < n; i++) {
                j = Math.floor(Math.random() * i);
                a[i] = a[j];
                a[j] = i;
            }
            return a;
        };

        var alt_flag = function() {
            var flag = true;
            return {
                csp$channel$Handler$active: function(o) { return flag;},
                csp$channel$Handler$commit: function(o) {
                    flag = null;
                    return true;
                }
            };
        };
        var alt_handler = function(flag, cb) {
            return {
                csp$channel$Handler$active: function(o) { return impl.active(flag);},
                csp$channel$Handler$commit: function(o) {
                    impl.commit(flag);
                    return cb;
                }
            };
        };
        return {
            chan: function(buffer) {
                return new Channel([], [], buffer, null);
            },
            take: function(port, fn1, on_caller) {
                on_caller = on_caller || true;
                var ret = impl.take(port, handler(fn1));
                if (ret) {
                    var val = impl.deref(ret);
                    if (on_caller) {
                        fn1(val);
                    } else {
                        run(function() { return fn1(val);});
                    }
                }
                return null;
            },
            put: function(port, val, fn0, on_caller) {
                fn0 = fn0 || nop;
                on_caller = on_caller || true;
                var ret = impl.put(port, val, handler(fn0));
                if (ret && (fn0  !== nop)) {
                    if (on_caller) {
                        fn0();
                    } else {
                        run(fn0);
                    }
                }
                return null;
            },
            close: function(port) {
                return impl.close(port);
            },
            closed: function(port) {
                return impl.closed(port);
            },
            alts: function(ports, fret, options) {
                options = options || {};
                var flag = alt_flag(),
                    n = ports.length,
                    idxs = random_array(n),
                    priority = (options.hasOwnProperty('priority')),
                    ret, i, idx, wport, port, val, h, vbox;
                for(i = 0; i < n; i++) {
                    idx = priority ? i : idxs[i];
                    port = ports[idx];
                    wport = (port.constructor === Array) ? port[0] : null;
                    h = (function(wport, port){
                        if (wport) {
                            return alt_handler(flag, function() { return fret(null, wport);});
                        }
                        return alt_handler(flag, function(v) { return fret(v, port);});
                    })(wport, port);
                    if (wport) {
                        vbox = impl.put(wport, port[1], h);
                    } else {
                        vbox = impl.take(port, h);
                    }
                    if (vbox) {
                        ret = box([impl.deref(vbox), (wport ? wport : port)]);
                    }
                }
                if (ret) {
                    return ret;
                }
                if (options.hasOwnProperty('default')) {
                    if (impl.active(flag) && impl.commit(flag)) {
                        box([options['default'], 'default']);
                    }
                }
                return null;
            },
            fixed_buffer: function(n) {
                return new Buffers.Fixed([], n);
            },
            dropping_buffer : function(n) {
                return new Buffers.Dropping([], n);
            },
            sliding_buffer: function(n) {
                return new Buffers.Sliding([], n);
            }
        };
    })(impl, util.handler, dispatch.run, Buffers, box);
    return {
        "impl": {
            "cleanup": impl.cleanup,
            "take": impl.take,
            "put": impl.put,
            "close": impl.close,
            "closed": impl.closed,
            "full": impl.full,
            "remove": impl.remove,
            "add": impl.add,
            "active": impl.active,
            "commit": impl.commit,
            "deref": impl.deref
        },
        "types": {
            "Channel": Channel,
            "FixedBuffer": Buffers.Fixed,
            "DroppingBuffer": Buffers.Dropping,
            "SlidingBuffer": Buffers.Sliding
        },
        "util": {
            "handler": util.handler
        },
        "chan": show.chan,
        "take": show.take,
        "put": show.put,
        "close": show.close,
        "closed": show.closed,
        "alts": show.alts,
        "fixed_buffer": show.fixed_buffer,
        "dropping_buffer": show.dropping_buffer,
        "sliding_buffer": show.sliding_buffer
    };
})();
<|endoftext|>


<commit_before>var fs = require('fs')
var os = require('os')
var join = require('path').join
var lruCache = require('lru-cache')
var readTorrent = require('read-torrent')
var torrentStream = require('torrent-stream')
var debug = require('debug')('back-row:torrent')
var mkdirp = require('mkdirp')
var parseTorrent = require('parse-torrent')

var TORRENT_PATH = process.env.TORRENT_CACHE_PATH || join(os.tmpDir(), 'back-row')
var TORRENT_INFO_HASH_PATH = join(TORRENT_PATH, 'info-hash')

/**
 * Create a torrent cache.
 *
 * @type {LRUCache}
 */
var TORRENT_CACHE = lruCache({
  max: process.env.TORRENT_CACHE_LIMIT || 10 * 1000 * 1000 * 1000, // 10GB
  length: torrentLength,
  dispose: disposeTorrent
})

/**
 * Keep track of the latest torrent downloads.
 *
 * @type {LRUCache}
 */
var URI_CACHE = lruCache(100) /* { [infoHash: string]: engine } */

/**
 * Dispose of the torrent.
 *
 * @param {String} key
 * @param {Object} torrent
 */
function disposeTorrent (key, torrent) {
  removeTorrent(torrent, logError)
}

/**
 * Remove the torrent from the filesystem.
 *
 * @param {Object}   torrent
 * @param {Function} cb
 */
function removeTorrent (engine, cb) {
  engine.remove(function (rmError) {
    fs.unlink(join(TORRENT_INFO_HASH_PATH, engine.infoHash), function (unlinkError) {
      cb(rmError || unlinkError)
    })
  })
}

/**
 * Return the torrent download size.
 *
 * @param  {Object} torrent
 * @return {Number}
 */
function torrentLength (engine) {
  return engine.torrent ? engine.torrent.length : 0
}

/**
 * Export the torrent stream.
 */
module.exports = torrent

/**
 * Create a torrent stream.
 *
 * @param {String}   uri
 * @param {Function} done
 */
function torrent (uri, done) {
  if (!/^magnet:|^https?:\/\//i.test(uri)) {
    return done(new Error('Unknown torrent specified'))
  }

  debug('torrent', uri)

  return createTorrentFromLocation(uri, done)
}

/**
 * Create a torrent stream from a uri.
 *
 * @param {String}   uri
 * @param {Function} done
 */
function createTorrentFromLocation (uri, done) {
  function next (err, torrent) {
    if (err) {
      return done(err)
    }

    if (/https?:\/\//i.test(uri)) {
      URI_CACHE.set(uri, torrent)
    }

    return createTorrent(torrent, done)
  }

  if (URI_CACHE.has(uri)) {
    return next(null, URI_CACHE.get(uri))
  }

  return readTorrent(uri, next)
}

/**
 * Create a torrent engine from an object.
 *
 * @param {Object}   torrent
 * @param {Function} done
 */
function createTorrent (torrent, done) {
  var engine = TORRENT_CACHE.get(torrent.infoHash)
  var exists = !!engine

  if (!engine) {
    engine = createEngine(torrent)

    TORRENT_CACHE.set(engine.infoHash, engine)
  }

  function next (engine) {
    // Avoid unnecessary torrent persistence creation.
    if (exists) {
      return done(null, engine)
    }

    return mkdirp(TORRENT_INFO_HASH_PATH, function (err) {
      if (err) {
        return done(err)
      }

      var buf = parseTorrent.toTorrentFile(engine.torrent)
      var path = join(TORRENT_INFO_HASH_PATH, engine.infoHash + '.torrent')

      return fs.writeFile(path, buf, function (err) {
        return done(err, engine)
      })
    })
  }

  if (engine.torrent) {
    return next(engine)
  }

  return engine.on('ready', function () {
    return next(engine)
  })
}

/**
 * Create a new torrent stream.
 *
 * @param  {String} uri
 * @return {Object}
 */
function createEngine (uri) {
  var engine = torrentStream(uri, {
    tmp: TORRENT_PATH
  })

  engine.on('error', logError)
  engine.on('interested', function () { engine.swarm.resume() })
  engine.on('uninterested', function () { engine.swarm.pause() })

  return engine
}

/**
 * Log an error callback that isn't handled otherwise.
 *
 * @param {Error} err
 */
function logError (err) {
  if (err) {
    console.log(err)
  }
}

/**
 * Create and/or read existing torrent files into application. This is an
 * in-memory solution to keeping the cache within the defined limit.
 */
(function () {
  try {
    fs.statSync(TORRENT_INFO_HASH_PATH)
  } catch (e) {
    return // Ignore rebooting when hashes are empty.
  }

  var hashes = fs.readdirSync(TORRENT_INFO_HASH_PATH)

  console.log('Found ' + hashes.length + ' hashes in ' + TORRENT_INFO_HASH_PATH)

  hashes.forEach(function (hash) {
    var filename = join(TORRENT_INFO_HASH_PATH, hash)
    var torrent = parseTorrent(fs.readFileSync(filename))

    console.log('Restarting torrent stream:', torrent.name)

    return createTorrent(torrent, logError)
  })
})()
<commit_msg>Use consistent hash file name logic<commit_after>var fs = require('fs')
var os = require('os')
var join = require('path').join
var lruCache = require('lru-cache')
var readTorrent = require('read-torrent')
var torrentStream = require('torrent-stream')
var debug = require('debug')('back-row:torrent')
var mkdirp = require('mkdirp')
var parseTorrent = require('parse-torrent')

var TORRENT_PATH = process.env.TORRENT_CACHE_PATH || join(os.tmpDir(), 'back-row')
var TORRENT_INFO_HASH_PATH = join(TORRENT_PATH, 'info-hash')

/**
 * Create a torrent cache.
 *
 * @type {LRUCache}
 */
var TORRENT_CACHE = lruCache({
  max: process.env.TORRENT_CACHE_LIMIT || 10 * 1000 * 1000 * 1000, // 10GB
  length: torrentLength,
  dispose: disposeTorrent
})

/**
 * Keep track of the latest torrent downloads.
 *
 * @type {LRUCache}
 */
var URI_CACHE = lruCache(100) /* { [infoHash: string]: engine } */

/**
 * Dispose of the torrent.
 *
 * @param {String} key
 * @param {Object} torrent
 */
function disposeTorrent (key, torrent) {
  removeTorrent(torrent, logError)
}

/**
 * Remove the torrent from the filesystem.
 *
 * @param {Object}   torrent
 * @param {Function} cb
 */
function removeTorrent (engine, cb) {
  engine.remove(function (rmError) {
    fs.unlink(cacheFilename(engine), function (unlinkError) {
      cb(rmError || unlinkError)
    })
  })
}

/**
 * Return the torrent download size.
 *
 * @param  {Object} torrent
 * @return {Number}
 */
function torrentLength (engine) {
  return engine.torrent ? engine.torrent.length : 0
}

/**
 * Return a consistent file location for torrents.
 *
 * @param  {Object} engine
 * @return {String}
 */
function cacheFilename (engine) {
  return join(TORRENT_INFO_HASH_PATH, engine.infoHash + '.torrent')
}

/**
 * Export the torrent stream.
 */
module.exports = torrent

/**
 * Create a torrent stream.
 *
 * @param {String}   uri
 * @param {Function} done
 */
function torrent (uri, done) {
  if (!/^magnet:|^https?:\/\//i.test(uri)) {
    return done(new Error('Unknown torrent specified'))
  }

  debug('torrent', uri)

  return createTorrentFromLocation(uri, done)
}

/**
 * Create a torrent stream from a uri.
 *
 * @param {String}   uri
 * @param {Function} done
 */
function createTorrentFromLocation (uri, done) {
  function next (err, torrent) {
    if (err) {
      return done(err)
    }

    if (/https?:\/\//i.test(uri)) {
      URI_CACHE.set(uri, torrent)
    }

    return createTorrent(torrent, done)
  }

  if (URI_CACHE.has(uri)) {
    return next(null, URI_CACHE.get(uri))
  }

  return readTorrent(uri, next)
}

/**
 * Create a torrent engine from an object.
 *
 * @param {Object}   torrent
 * @param {Function} done
 */
function createTorrent (torrent, done) {
  var engine = TORRENT_CACHE.get(torrent.infoHash)
  var exists = !!engine

  if (!engine) {
    engine = createEngine(torrent)

    TORRENT_CACHE.set(engine.infoHash, engine)
  }

  function next (engine) {
    // Avoid unnecessary torrent persistence creation.
    if (exists) {
      return done(null, engine)
    }

    return mkdirp(TORRENT_INFO_HASH_PATH, function (err) {
      if (err) {
        return done(err)
      }

      var buf = parseTorrent.toTorrentFile(engine.torrent)

      return fs.writeFile(cacheFilename(engine), buf, function (err) {
        return done(err, engine)
      })
    })
  }

  if (engine.torrent) {
    return next(engine)
  }

  return engine.on('ready', function () {
    return next(engine)
  })
}

/**
 * Create a new torrent stream.
 *
 * @param  {String} uri
 * @return {Object}
 */
function createEngine (uri) {
  var engine = torrentStream(uri, {
    tmp: TORRENT_PATH
  })

  engine.on('error', logError)
  engine.on('interested', function () { engine.swarm.resume() })
  engine.on('uninterested', function () { engine.swarm.pause() })

  return engine
}

/**
 * Log an error callback that isn't handled otherwise.
 *
 * @param {Error} err
 */
function logError (err) {
  if (err) {
    console.log(err)
  }
}

/**
 * Create and/or read existing torrent files into application. This is an
 * in-memory solution to keeping the cache within the defined limit.
 */
(function () {
  try {
    fs.statSync(TORRENT_INFO_HASH_PATH)
  } catch (e) {
    return // Ignore rebooting when hashes are empty.
  }

  var hashes = fs.readdirSync(TORRENT_INFO_HASH_PATH)

  console.log('Found ' + hashes.length + ' hashes in ' + TORRENT_INFO_HASH_PATH)

  hashes.forEach(function (hash) {
    var filename = join(TORRENT_INFO_HASH_PATH, hash)
    var torrent = parseTorrent(fs.readFileSync(filename))

    console.log('Restarting torrent stream:', torrent.name)

    return createTorrent(torrent, logError)
  })
})()
<|endoftext|>


<commit_before>'use strict';

var helpers = require('../helpers'),
    yaml = require('js-yaml'),
    fs = require('fs'),
    path = require('path');

var properties = yaml.safeLoad(fs.readFileSync(path.join(__dirname, '../../data', 'properties.yml'), 'utf8')).split(' ');

module.exports = {
  'name': 'property-spelling',
  'defaults': {
    'extra-properties': []
  },
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('property', function (node) {
      if (node.first().is('ident')) {
        var curProperty = node.first().content;

        if (curProperty.charAt(0) === '-') {
          curProperty = helpers.stripPrefix(curProperty);

        }

        if (properties.indexOf(curProperty) === -1 && parser.options['extra-properties'].indexOf(curProperty) === -1) {
          result = helpers.addUnique(result, {
            'ruleId': parser.rule.name,
            'line': node.start.line,
            'column': node.start.column,
            'message': 'Property `' + curProperty + '` appears to be spelt incorrectly',
            'severity': parser.severity
          });

        }
      }
    });
    return result;
  }
};
<commit_msg>Update to use US English<commit_after>'use strict';

var helpers = require('../helpers'),
    yaml = require('js-yaml'),
    fs = require('fs'),
    path = require('path');

var properties = yaml.safeLoad(fs.readFileSync(path.join(__dirname, '../../data', 'properties.yml'), 'utf8')).split(' ');

module.exports = {
  'name': 'property-spelling',
  'defaults': {
    'extra-properties': []
  },
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('property', function (node) {
      if (node.first().is('ident')) {
        var curProperty = node.first().content;

        if (curProperty.charAt(0) === '-') {
          curProperty = helpers.stripPrefix(curProperty);

        }

        if (properties.indexOf(curProperty) === -1 && parser.options['extra-properties'].indexOf(curProperty) === -1) {
          result = helpers.addUnique(result, {
            'ruleId': parser.rule.name,
            'line': node.start.line,
            'column': node.start.column,
            'message': 'Property `' + curProperty + '` appears to be spelled incorrectly',
            'severity': parser.severity
          });

        }
      }
    });
    return result;
  }
};
<|endoftext|>


<commit_before>export default (githubClient, git, logger, parsedContent) => {
    const prepareCommit = function* (fixRequest, fix, parent) {
        const newBlob = {
            ...fix.blob,
            content: fix.content,
            mode: '100644',
        };

        yield git.add(newBlob, `/${fixRequest.comment.path}`);

        const message = `Typo fix s/${fix.match.from}/${fix.match.to}/

As requested by ${parsedContent.sender} at ${fixRequest.comment.url}`;

        return yield git.commit(parsedContent.pullRequest.ref, message, parent);
    };

    const init = function* () {
        yield git.checkout(parsedContent.pullRequest.ref);
    };

    const prepareFix = function* (fixRequest, fix, defaultLastCommitSha = null) {
        const commit = yield prepareCommit(fixRequest, fix, defaultLastCommitSha);

        logger.info('Successful commit', { commitId: commit.sha });
        return commit.sha;
    };

    const push = function* (lastCommitSha) {
        if (lastCommitSha) {
            yield git.push(parsedContent.pullRequest.ref);
            logger.info('Successful pushed the branch', { branch: parsedContent.pullRequest.ref });

            return true;
        }

        return false;
    };

    return { init, prepareCommit, prepareFix, push };
};
<commit_msg>Typo fix s/Successful/Successfully/<commit_after>export default (githubClient, git, logger, parsedContent) => {
    const prepareCommit = function* (fixRequest, fix, parent) {
        const newBlob = {
            ...fix.blob,
            content: fix.content,
            mode: '100644',
        };

        yield git.add(newBlob, `/${fixRequest.comment.path}`);

        const message = `Typo fix s/${fix.match.from}/${fix.match.to}/

As requested by ${parsedContent.sender} at ${fixRequest.comment.url}`;

        return yield git.commit(parsedContent.pullRequest.ref, message, parent);
    };

    const init = function* () {
        yield git.checkout(parsedContent.pullRequest.ref);
    };

    const prepareFix = function* (fixRequest, fix, defaultLastCommitSha = null) {
        const commit = yield prepareCommit(fixRequest, fix, defaultLastCommitSha);

        logger.info('Successful commit', { commitId: commit.sha });
        return commit.sha;
    };

    const push = function* (lastCommitSha) {
        if (lastCommitSha) {
            yield git.push(parsedContent.pullRequest.ref);
            logger.info('Successfully pushed the branch', { branch: parsedContent.pullRequest.ref });

            return true;
        }

        return false;
    };

    return { init, prepareCommit, prepareFix, push };
};
<|endoftext|>


<commit_before>function TTYPlayer () {
	var binary = null;
	var ttyrec = null;
	var index = -1;

	var frame = $('#frame');
	var buffer = [[]];
	var output = '';
	var pre_pend = '';
	var point = {
		x: 1, y: 1
	};

	var render_frame = function (string) {
		string = pre_pend + string;
		pre_pend = '';

		output = string;

		var regexp = new RegExp('\\x1b[[][?]?([0-9;]*)([A-Za-z])');
		var part_regexp = new RegExp('\\x1b[[][?]?([0-9;]*)');
		var span = {
			foreground: 'white',
			background: 'black',
			light: '',
			negative: false
		};

		var output_characters = function (index) {
			var substring = '';

			if (index == -1) {
				substring = string;
				string = '';
			}
			else {
				substring = string.slice(0, index);
				string = string.slice(index);
			}

			var pre = '';

			var post = '';

			for (var i in substring) {
				var character = substring[i];
				var code = character.charCodeAt(0);

				if (code < 32) {
					if (code == 8) {
						// Backspace
						point.x--;
					}
					else if (code == 13) {
						// Carriage return
						point.x = 1;
						point.y++;
						if (buffer[point.y - 1] == undefined) {
							buffer[point.y - 1] = [];
						}
					}
					else {
						console.error('Unhandled non-printing character, code: ' + code);
					}
				}
				else {
					if (character == ' ') {
						character = ' ';
					}

					buffer[point.y - 1][point.x - 1] = pre + character + post;
					point.x++;
				}
			}
		};

		var handle_esc = function() {

			var init_rows = function(n) {
				for (var i = 0; i < n; i++) {
					if (buffer[point.y + i] == undefined) {
						buffer[point.y + i] = [];
					}
				}
			};

			var cursor_up = function(n) {
				if (point.y == 1) return;
				if (isNaN(n)) n = 1;

				point.y -= n;

				if (point.y < 1) point.y = 1;
			};

			var cursor_down = function(n) {
				if (isNaN(n)) n = 1;

				init_rows(n);
				point.y += n;
			};

			var cursor_forward = function(n) {
				if (isNaN(n)) n = 1;

				point.x += n;
			};

			var cursor_back = function(n) {
				if (point.x == 1) return;
				if (isNaN(n)) n = 1;

				point.x -= n;

				if (point.x < 1) point.x = 1;
			};

			var cursor_next_line = function(n) {
				cursor_down(n);
				point.x = 1;
			};

			var cursor_prev_line = function(n) {
				cursor_up(n);
				point.x = 1;
			};

			var cursor_horizontal_absolute = function(n) {
				if (isNaN(n)) {
					console.error('Undefined behaviour for cursor_horizontal_absolute');
					return;
				}

				point.x = n;
			};

			var cursor_position = function(row, column) {
				if (row < point.y) {
					cursor_up(point.y - row);
				}
				else if (row > point.y) {
					cursor_down(row - point.y);
				}

				point.x = column;
			};

			var erase_data = function(n) {
				if (isNaN(n)) n = 0;
				if (n == 0) {
					// Clear from the cursor to the end of the buffer.
					buffer[point.y - 1].splice(point.x - 1);
					buffer.splice(point.y - 1);
				}
				else if (n == 1) {
					// Clear from the cursor to beginning of buffer.
					for (var i = 0; i < point.y - 1; i++) {
						buffer[i] = [];
					}

					for (var j = 0; j < point.x; j++) {
						buffer[point.y - 1][j] = undefined;
					}
				}
				else if (n == 2) {
					buffer = [[]];

					// Moving the cursor might not be the right behaviour.
					point.x = 1;
					point.y = 1;
				}
				else {
					console.error('Undefined behaviour for erase_data.');
				}
			};

			var erase_in_line = function(n) {
				if (isNaN(n)) n = 0;
				if (n == 0) {
					buffer[point.y - 1].splice(point.x - 1);
				}
				else if (n == 1) {
					for (var i = 0; i < point.x; i++) {
						buffer[point.y - 1][i] = undefined;
					}
				}
				else if (n == 2) {
					buffer[point.y - 1] = [];
				}
				else {
					console.error('Undefined behaviour for erase_in_line.');
				}
			};

			var delete_characters = function(n) {
				for (var i = 0; i < n; i++) {
					buffer[point.y - 1][point.x + i] = undefined;
				}
				cursor_forward(n);
			};

			var select_graphic_rendition = function(value) {
				if (value == '') {
					span.foreground = 'white';
					span.background = 'black';
					span.light = '';
				}
				else {
					var values = value.split(';');
					var l = values.length;
					for (var i = 0; i < l; i++) {
						var val = values[i];
						if (val == '0') {
							span.foreground = 'white';
							span.background = 'black';
							span.light = '';
							span.negative = false;
						}
						else if (val == '1') {
							span.light = 'light-';
						}
						else if (val == '5') {
							// Blink.
						}
						else if (val == '7') {
							span.negative = true;
						}
						else if (val == '30') {
							span.foreground = 'black';
						}
						else if (val == '31') {
							span.foreground = 'red';
						}
						else if (val == '32') {
							span.foreground = 'green';
						}
						else if (val == '33') {
							span.foreground = 'yellow';
						}
						else if (val == '34') {
							span.foreground = 'blue';
						}
						else if (val == '35') {
							span.foreground = 'magenta';
						}
						else if (val == '36') {
							span.foreground = 'cyan';
						}
						else if (val == '37') {
							span.foreground = 'white';
						}
						else if (val == '39') {
							span.foreground = 'white';
						}
						else if (val == '40') {
							span.background = 'black';
						}
						else if (val == '41') {
							span.background = 'red';
						}
						else if (val == '42') {
							span.background = 'green';
						}
						else if (val == '43') {
							span.background = 'yellow';
						}
						else if (val == '44') {
							span.background = 'blue';
						}
						else if (val == '45') {
							span.background = 'magenta';
						}
						else if (val == '46') {
							span.background = 'cyan';
						}
						else if (val == '47') {
							span.background = 'white';
						}
						else if (val == '49') {
							span.background = 'black';
						}
						else {
							console.error('Unhandled SGR parameter: ' + val);
						}
					}
				}
			};

			var match = string.match(regexp);
			var c = match[2];
			var value = match[1];
			var n = parseInt(value);

			if (c == 'A') {
				cursor_up(n);
			}
			else if (c == 'B') {
				cursor_down(n);
			}
			else if (c == 'C') {
				cursor_forward(n);
			}
			else if (c == 'D') {
				cursor_back(n);
			}
			else if (c == 'E') {
				cursor_next_line(n);
			}
			else if (c == 'F') {
				cursor_prev_line(n);
			}
			else if (c == 'G') {
				cursor_horizontal_absolute(n);
			}
			else if (c == 'H') {
				var x = 1;
				var y = 1;
				if (value != '') {
					var values = value.split(';');
					if (values[0] != '') y = parseInt(values[0]);
					if (values.length == 2) x = parseInt(values[1]);
				}
				cursor_position(y, x);
			}
			else if (c == 'J') {
				erase_data(n);
			}
			else if (c == 'K') {
				erase_in_line(n);
			}
			else if (c == 'S') {
				console.error('scroll_up not defined.');
			}
			else if (c == 'T') {
				console.error('scroll_down not defined.');
			}
			else if (c == 'X') {
				// Delete n characters to the right of the point?
				delete_characters(n);
			}
			else if (c == 'f') {
				var x = 1;
				var y = 1;
				if (value != '') {
					var values = value.split(';');
					if (values[0] != '') y = parseInt(values[0]);
					if (values.length == 2) x = parseInt(values[1]);
				}
				cursor_position(y, x);
			}
			else if (c == 'm') {
				select_graphic_rendition(value);
			}
			else if (c == 'd') {
				// Move the point downwards?
				cursor_position(n, point.x);
			}
			else if (match[0] == '[?25l') {
				console.error('hide_cursor not defined.');
			}
			else if (match[0] == '[?25h') {
				console.error('show_cursor not defined.');
			}
			else {
				console.error('Unhandled escape sequence: ' + match[0]);
			}

			string = string.slice(match[0].length);
		};

		var print_buffer = function () {
			frame.empty();

			var m = buffer.length;
			for	(var i = 0; i < m; i++) {
				var row = buffer[i];
				var n = row.length;
				for (var j = 0; j < n; j++) {
					var character = row[j];
					if (character == undefined) {
						character = ' ';
					}
					frame.append(character);
				}
				frame.append('
');
			}

			for (var j = 0; j + m < 24; j++) {
				frame.append('
');
			}
		};

		// Remove shift-in and shift-out, as I have no idea what to do with them.
		string = string.replace(/\x0f/g, '');
		string = string.replace(/\x0e/g, '');

		while (string != '') {
			var index = string.search(regexp);

			if (index == -1) {
				// Have to see if the last few characters are a code that's been cut-off.
				if (string.search(part_regexp) != -1) {
					pre_pend = string;
					string = '';
				}
				else {
					output_characters(index);
				}
			}
			else if ( index > 0) {
				output_characters(index);
			}
			else if (index == 0) {
				handle_esc();
			}
		}

		print_buffer();
	};

	var print_frame = function(i) {
		var t = ttyrec[i];
		var s = binary.getStringAt(t.address, t.len);
		p.render_frame(s);
	};

	return {
		get_buffer: function() {
			return buffer;
		},

		get_index: function() {
			return index;
		},

		get_output: function() {
			return output;
		},

		get_point: function() {
			return point;
		},

		get_prepend: function() {
			return pre_pend;
		},

		get_ttyrec: function() {
			return ttyrec;
		},

		clear_frame: function() {
			buffer = [[]];
			point = { x:1, y: 1};
			render_frame('');
		},

		print_frame: print_frame,

		next_frame: function() {
			if (index < ttyrec.length) {
				index += 1;
				print_frame(index);
			}
		},

		previous_frame: function() {
			if (index > 0) {
				index -= 1;
				print_frame(index);
			}
		},

		set_frame: function(n) {
			index = n;
			print_frame(index);
		},

		parse_data: function (input) {
			binary = input.binaryResponse;
			ttyrec = [];

			var length = binary.getLength();
			var offset = 0;

			while (offset < length) {
				var sec = binary.getLongAt(offset + 0, false);
				var usec = binary.getLongAt(offset + 4, false);
				var len = binary.getLongAt(offset + 8, false);
				var address = offset + 12;

				ttyrec.push({
								sec: sec,
								usec: usec,
								len: len,
								address: address
							});

				offset += (12 + len);
			}
		},

		render_frame: render_frame
	};
};

var p;

$().ready(function() {
			  p = TTYPlayer();
			  BinaryAjax('Spec.ttyrec', function (data) { p.parse_data(data); p.set_frame(6); });
		  });

$('html').keydown(function(event) {
				if (event.keyCode == '37') {
					p.previous_frame();
				}
				else if (event.keyCode == '39') {
					p.next_frame();
				}
			});
<commit_msg>delete_characters shouldn't move the cursor forwards.<commit_after>function TTYPlayer () {
	var binary = null;
	var ttyrec = null;
	var index = -1;

	var frame = $('#frame');
	var buffer = [[]];
	var output = '';
	var pre_pend = '';
	var point = {
		x: 1, y: 1
	};

	var render_frame = function (string) {
		string = pre_pend + string;
		pre_pend = '';

		output = string;

		var regexp = new RegExp('\\x1b[[][?]?([0-9;]*)([A-Za-z])');
		var part_regexp = new RegExp('\\x1b[[][?]?([0-9;]*)');
		var span = {
			foreground: 'white',
			background: 'black',
			light: '',
			negative: false
		};

		var output_characters = function (index) {
			var substring = '';

			if (index == -1) {
				substring = string;
				string = '';
			}
			else {
				substring = string.slice(0, index);
				string = string.slice(index);
			}

			var pre = '';

			var post = '';

			for (var i in substring) {
				var character = substring[i];
				var code = character.charCodeAt(0);

				if (code < 32) {
					if (code == 8) {
						// Backspace
						point.x--;
					}
					else if (code == 13) {
						// Carriage return
						point.x = 1;
						point.y++;
						if (buffer[point.y - 1] == undefined) {
							buffer[point.y - 1] = [];
						}
					}
					else {
						console.error('Unhandled non-printing character, code: ' + code);
					}
				}
				else {
					if (character == ' ') {
						character = ' ';
					}

					buffer[point.y - 1][point.x - 1] = pre + character + post;
					point.x++;
				}
			}
		};

		var handle_esc = function() {

			var init_rows = function(n) {
				for (var i = 0; i < n; i++) {
					if (buffer[point.y + i] == undefined) {
						buffer[point.y + i] = [];
					}
				}
			};

			var cursor_up = function(n) {
				if (point.y == 1) return;
				if (isNaN(n)) n = 1;

				point.y -= n;

				if (point.y < 1) point.y = 1;
			};

			var cursor_down = function(n) {
				if (isNaN(n)) n = 1;

				init_rows(n);
				point.y += n;
			};

			var cursor_forward = function(n) {
				if (isNaN(n)) n = 1;

				point.x += n;
			};

			var cursor_back = function(n) {
				if (point.x == 1) return;
				if (isNaN(n)) n = 1;

				point.x -= n;

				if (point.x < 1) point.x = 1;
			};

			var cursor_next_line = function(n) {
				cursor_down(n);
				point.x = 1;
			};

			var cursor_prev_line = function(n) {
				cursor_up(n);
				point.x = 1;
			};

			var cursor_horizontal_absolute = function(n) {
				if (isNaN(n)) {
					console.error('Undefined behaviour for cursor_horizontal_absolute');
					return;
				}

				point.x = n;
			};

			var cursor_position = function(row, column) {
				if (row < point.y) {
					cursor_up(point.y - row);
				}
				else if (row > point.y) {
					cursor_down(row - point.y);
				}

				point.x = column;
			};

			var erase_data = function(n) {
				if (isNaN(n)) n = 0;
				if (n == 0) {
					// Clear from the cursor to the end of the buffer.
					buffer[point.y - 1].splice(point.x - 1);
					buffer.splice(point.y - 1);
				}
				else if (n == 1) {
					// Clear from the cursor to beginning of buffer.
					for (var i = 0; i < point.y - 1; i++) {
						buffer[i] = [];
					}

					for (var j = 0; j < point.x; j++) {
						buffer[point.y - 1][j] = undefined;
					}
				}
				else if (n == 2) {
					buffer = [[]];

					// Moving the cursor might not be the right behaviour.
					point.x = 1;
					point.y = 1;
				}
				else {
					console.error('Undefined behaviour for erase_data.');
				}
			};

			var erase_in_line = function(n) {
				if (isNaN(n)) n = 0;
				if (n == 0) {
					buffer[point.y - 1].splice(point.x - 1);
				}
				else if (n == 1) {
					for (var i = 0; i < point.x; i++) {
						buffer[point.y - 1][i] = undefined;
					}
				}
				else if (n == 2) {
					buffer[point.y - 1] = [];
				}
				else {
					console.error('Undefined behaviour for erase_in_line.');
				}
			};

			var delete_characters = function(n) {
				for (var i = 0; i < n; i++) {
					buffer[point.y - 1][point.x + i] = undefined;
				}
			};

			var select_graphic_rendition = function(value) {
				if (value == '') {
					span.foreground = 'white';
					span.background = 'black';
					span.light = '';
				}
				else {
					var values = value.split(';');
					var l = values.length;
					for (var i = 0; i < l; i++) {
						var val = values[i];
						if (val == '0') {
							span.foreground = 'white';
							span.background = 'black';
							span.light = '';
							span.negative = false;
						}
						else if (val == '1') {
							span.light = 'light-';
						}
						else if (val == '5') {
							// Blink.
						}
						else if (val == '7') {
							span.negative = true;
						}
						else if (val == '30') {
							span.foreground = 'black';
						}
						else if (val == '31') {
							span.foreground = 'red';
						}
						else if (val == '32') {
							span.foreground = 'green';
						}
						else if (val == '33') {
							span.foreground = 'yellow';
						}
						else if (val == '34') {
							span.foreground = 'blue';
						}
						else if (val == '35') {
							span.foreground = 'magenta';
						}
						else if (val == '36') {
							span.foreground = 'cyan';
						}
						else if (val == '37') {
							span.foreground = 'white';
						}
						else if (val == '39') {
							span.foreground = 'white';
						}
						else if (val == '40') {
							span.background = 'black';
						}
						else if (val == '41') {
							span.background = 'red';
						}
						else if (val == '42') {
							span.background = 'green';
						}
						else if (val == '43') {
							span.background = 'yellow';
						}
						else if (val == '44') {
							span.background = 'blue';
						}
						else if (val == '45') {
							span.background = 'magenta';
						}
						else if (val == '46') {
							span.background = 'cyan';
						}
						else if (val == '47') {
							span.background = 'white';
						}
						else if (val == '49') {
							span.background = 'black';
						}
						else {
							console.error('Unhandled SGR parameter: ' + val);
						}
					}
				}
			};

			var match = string.match(regexp);
			var c = match[2];
			var value = match[1];
			var n = parseInt(value);

			if (c == 'A') {
				cursor_up(n);
			}
			else if (c == 'B') {
				cursor_down(n);
			}
			else if (c == 'C') {
				cursor_forward(n);
			}
			else if (c == 'D') {
				cursor_back(n);
			}
			else if (c == 'E') {
				cursor_next_line(n);
			}
			else if (c == 'F') {
				cursor_prev_line(n);
			}
			else if (c == 'G') {
				cursor_horizontal_absolute(n);
			}
			else if (c == 'H') {
				var x = 1;
				var y = 1;
				if (value != '') {
					var values = value.split(';');
					if (values[0] != '') y = parseInt(values[0]);
					if (values.length == 2) x = parseInt(values[1]);
				}
				cursor_position(y, x);
			}
			else if (c == 'J') {
				erase_data(n);
			}
			else if (c == 'K') {
				erase_in_line(n);
			}
			else if (c == 'S') {
				console.error('scroll_up not defined.');
			}
			else if (c == 'T') {
				console.error('scroll_down not defined.');
			}
			else if (c == 'X') {
				delete_characters(n);
			}
			else if (c == 'f') {
				var x = 1;
				var y = 1;
				if (value != '') {
					var values = value.split(';');
					if (values[0] != '') y = parseInt(values[0]);
					if (values.length == 2) x = parseInt(values[1]);
				}
				cursor_position(y, x);
			}
			else if (c == 'm') {
				select_graphic_rendition(value);
			}
			else if (c == 'd') {
				// Move the point downwards?
				cursor_position(n, point.x);
			}
			else if (match[0] == '[?25l') {
				console.error('hide_cursor not defined.');
			}
			else if (match[0] == '[?25h') {
				console.error('show_cursor not defined.');
			}
			else {
				console.error('Unhandled escape sequence: ' + match[0]);
			}

			string = string.slice(match[0].length);
		};

		var print_buffer = function () {
			frame.empty();

			var m = buffer.length;
			for	(var i = 0; i < m; i++) {
				var row = buffer[i];
				var n = row.length;
				for (var j = 0; j < n; j++) {
					var character = row[j];
					if (character == undefined) {
						character = ' ';
					}
					frame.append(character);
				}
				frame.append('
');
			}

			for (var j = 0; j + m < 24; j++) {
				frame.append('
');
			}
		};

		// Remove shift-in and shift-out, as I have no idea what to do with them.
		string = string.replace(/\x0f/g, '');
		string = string.replace(/\x0e/g, '');

		while (string != '') {
			var index = string.search(regexp);

			if (index == -1) {
				// Have to see if the last few characters are a code that's been cut-off.
				if (string.search(part_regexp) != -1) {
					pre_pend = string;
					string = '';
				}
				else {
					output_characters(index);
				}
			}
			else if ( index > 0) {
				output_characters(index);
			}
			else if (index == 0) {
				handle_esc();
			}
		}

		print_buffer();
	};

	var print_frame = function(i) {
		var t = ttyrec[i];
		var s = binary.getStringAt(t.address, t.len);
		p.render_frame(s);
	};

	return {
		get_buffer: function() {
			return buffer;
		},

		get_index: function() {
			return index;
		},

		get_output: function() {
			return output;
		},

		get_point: function() {
			return point;
		},

		get_prepend: function() {
			return pre_pend;
		},

		get_ttyrec: function() {
			return ttyrec;
		},

		clear_frame: function() {
			buffer = [[]];
			point = { x:1, y: 1};
			render_frame('');
		},

		print_frame: print_frame,

		next_frame: function() {
			if (index < ttyrec.length) {
				index += 1;
				print_frame(index);
			}
		},

		previous_frame: function() {
			if (index > 0) {
				index -= 1;
				print_frame(index);
			}
		},

		set_frame: function(n) {
			index = n;
			print_frame(index);
		},

		parse_data: function (input) {
			binary = input.binaryResponse;
			ttyrec = [];

			var length = binary.getLength();
			var offset = 0;

			while (offset < length) {
				var sec = binary.getLongAt(offset + 0, false);
				var usec = binary.getLongAt(offset + 4, false);
				var len = binary.getLongAt(offset + 8, false);
				var address = offset + 12;

				ttyrec.push({
								sec: sec,
								usec: usec,
								len: len,
								address: address
							});

				offset += (12 + len);
			}
		},

		render_frame: render_frame
	};
};

var p;

$().ready(function() {
			  p = TTYPlayer();
			  BinaryAjax('foo.ttyrec', function (data) { p.parse_data(data); p.set_frame(6); });
		  });

$('html').keydown(function(event) {
				if (event.keyCode == '37') {
					p.previous_frame();
				}
				else if (event.keyCode == '39') {
					p.next_frame();
				}
			});
<|endoftext|>


<commit_before>/* eslint-env node, mocha */
'use strict';

const assert = require('chai').assert
    , router = require('./router')
    , events = require('harken')
    , routeObject = require('../test_stubs/routes_stub.json')
    , stream = require('stream')
    , req = {
        method: 'GET'
        , url: '/about'
        , headers: {}
    };

let res
    , routeHandler;

describe('Route Handler Tests', () => {
    beforeEach(() => {
        routeHandler = router(routeObject, { publicPath: './test_stubs/deletes' });

        res = new stream.Writable();

        res.setHeader = function (name, value) {
            this.headers[name] = value;
        };

        res.writeHead = function (status, headers) {
            this.statusCode = status;
            this.headers = Object.keys(headers).reduce((prevIn, key) => {
                const prev = prevIn;

                prev[key] = headers[key];

                return prev;
            }, this.headers);
        };

        res.statusCode = 0;
        res.headers = {};
        /* eslint-disable no-underscore-dangle */
        res._write = function (chunk, enc, cb) {
            const buffer = Buffer.isBuffer(chunk) ? chunk : new Buffer(chunk, enc);

            events.emit('response', buffer.toString());
            cb();
        };
        /* eslint-enable no-underscore-dangle */

        events.off('error:404');
        events.off('static:missing');
        events.off('response');
        events.off('route:/about:get');
        events.off('route:/api/articles/:id:get');
    });

    it('should be defined as a funciton', () => {
        assert.isFunction(router);
    });

    it('should return a function', () => {
        assert.isFunction(router(routeObject, { publicPath: './test_stubs/deletes' }));
    });

    describe('simple routes', () => {
        it('should emit the correct route event for a simple route', (done) => {
            events.once('route:/about:get', (connection) => {
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('security headers', () => {
        it('should return x-powered-by only if it is set', (done) => {
            const tempHandler = router(routeObject, {
                publicPath: './test_stubs/deletes'
                , security: { poweredBy: 'waffles' }
            });

            events.once('route:/about:get', (connection) => {
                assert.isObject(connection.res.headers);
                assert.strictEqual(connection.res.headers['X-Powered-By'], 'waffles');
                assert.isObject(connection);
                done();
            });

            tempHandler(req, res);
        });

        it('should by default not return x-powered-by ', (done) => {
            events.once('route:/about:get', (connection) => {
                assert.strictEqual(connection.res.headers['X-Powered-By'], undefined);
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('parameterized routes', () => {
        it('should emit the correct route event for a wildcard route', (done) => {
            req.url = '/api/articles/1234';

            events.once('route:/api/articles/:id:get', (connection) => {
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should pass variables on the connection.params from the url', (done) => {
            req.url = '/api/articles/1234/links/daniel';

            events.once('route:/api/articles/:id/links/:item:get', (connection) => {
                assert.isObject(connection);
                assert.strictEqual(connection.params.id, '1234');
                assert.strictEqual(connection.params.item, 'daniel');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('404 routes', () => {
        it('should emit the 404 route event for a 404 route', (done) => {
            req.url = '/about/daniel';

            events.once('error:404', (connection) => {
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('static file routes', () => {
        let etag;

        beforeEach(() => {
            etag = '"4b-ah1/iPV1wknehHVYGkU4jQ"';
        });

        it('should emit 404 & missing static events for missing file in sub of public', (done) => {
            req.url = '/static/somefile.js';

            events.required([ 'error:404', 'static:missing' ], (input) => {
                assert.isObject(input[0]);
                assert.isString(input[1]);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should emit 404 event for a non-existant static file in the root of public', (done) => {
            req.url = '/static/somefile.js';

            events.once('error:404', (input) => {
                assert.isObject(input);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return the file for an existing static file with no etag', (done) => {
            req.url = '/static/main.js';

            events.once('response', (input) => {
                assert.isString(input);
                assert.isAbove(input.length, 0);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should have a vary:accept-encoding header for static resources', (done) => {
            const successStatus = 200;

            req.url = '/static/main.js';
            req.method = 'get';
            req.headers['if-none-match'] = '';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                assert.isObject(res.headers);
                assert.strictEqual(res.headers.Vary, 'Accept-Encoding');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return a 304 for a valid etag match', (done) => {
            const unmodStatus = 304;

            req.url = '/static/main.js';
            req.headers['if-none-match'] = etag;

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, unmodStatus);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return just headers if a head request is sent', (done) => {
            const successStatus = 200;

            req.url = '/static/main.js';
            req.method = 'head';
            req.headers['if-none-match'] = '';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                assert.isObject(res.headers);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('route.json route', () => {
        it('should return the routes.json file when the router route is requested', (done) => {
            req.url = '/routes';

            events.once('response', (result) => {
                const resultObject = JSON.parse(result);

                assert.isObject(resultObject);
                assert.strictEqual(resultObject['/'][0], routeObject['/'][0]);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });

        });
    });

    describe('compression routes', () => {
        it('should return status code 200 for valid gzip compression', (done) => {
            const successStatus = 200;

            req.method = 'GET';
            req.url = '/static/main.js';
            req.headers['accept-encoding'] = 'gzip';
            res.compress = true;

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should have a content-encoding:gzip header for gzip compression', (done) => {
            res.on('finish', () => {
                assert.strictEqual(res.headers['Content-Encoding'], 'gzip');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should serve a file as a response with gzip compression', (done) => {
            events.once('response', (input) => {
                assert.isString(input);
                assert.isAbove(input.length, 0);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should emit served static events for files with gzip compression', (done) => {
            events.once('static:served', (pathname) => {
                assert.strictEqual(pathname, req.url);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return status code 200 for valid deflate compression', (done) => {
            const successStatus = 200;

            req.headers['accept-encoding'] = 'deflate';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should have a content-encoding:deflate header for deflate compression', (done) => {
            res.on('finish', () => {
                assert.strictEqual(res.headers['Content-Encoding'], 'deflate');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should serve a file as a response with deflate compression', (done) => {
            events.once('response', (input) => {
                assert.isString(input);
                assert.isAbove(input.length, 0);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should emit served static events for files with deflate compression', (done) => {
            events.once('static:served', (pathname) => {
                assert.strictEqual(pathname, req.url);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });
});
<commit_msg>Tests for status codes, headers, file returns and event emits for gzip/deflate compression in router_test.js<commit_after>/* eslint-env node, mocha */
'use strict';

const assert = require('chai').assert
    , router = require('./router')
    , events = require('harken')
    , routeObject = require('../test_stubs/routes_stub.json')
    , stream = require('stream')
    , req = {
        method: 'GET'
        , url: '/about'
        , headers: {}
    };

let res
    , routeHandler;

describe('Route Handler Tests', () => {
    beforeEach(() => {
        routeHandler = router(routeObject, { publicPath: './test_stubs/deletes' });

        res = new stream.Writable();

        res.setHeader = function (name, value) {
            this.headers[name] = value;
        };

        res.writeHead = function (status, headers) {
            this.statusCode = status;
            this.headers = Object.keys(headers).reduce((prevIn, key) => {
                const prev = prevIn;

                prev[key] = headers[key];

                return prev;
            }, this.headers);
        };

        res.statusCode = 0;
        res.headers = {};
        /* eslint-disable no-underscore-dangle */
        res._write = function (chunk, enc, cb) {
            const buffer = Buffer.isBuffer(chunk) ? chunk : new Buffer(chunk, enc);

            events.emit('response', buffer.toString());
            cb();
        };
        /* eslint-enable no-underscore-dangle */

        events.off('error:404');
        events.off('static:missing');
        events.off('response');
        events.off('route:/about:get');
        events.off('route:/api/articles/:id:get');
    });

    it('should be defined as a funciton', () => {
        assert.isFunction(router);
    });

    it('should return a function', () => {
        assert.isFunction(router(routeObject, { publicPath: './test_stubs/deletes' }));
    });

    describe('simple routes', () => {
        it('should emit the correct route event for a simple route', (done) => {
            events.once('route:/about:get', (connection) => {
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('security headers', () => {
        it('should return x-powered-by only if it is set', (done) => {
            const tempHandler = router(routeObject, {
                publicPath: './test_stubs/deletes'
                , security: { poweredBy: 'waffles' }
            });

            events.once('route:/about:get', (connection) => {
                assert.isObject(connection.res.headers);
                assert.strictEqual(connection.res.headers['X-Powered-By'], 'waffles');
                assert.isObject(connection);
                done();
            });

            tempHandler(req, res);
        });

        it('should by default not return x-powered-by ', (done) => {
            events.once('route:/about:get', (connection) => {
                assert.strictEqual(connection.res.headers['X-Powered-By'], undefined);
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('parameterized routes', () => {
        it('should emit the correct route event for a wildcard route', (done) => {
            req.url = '/api/articles/1234';

            events.once('route:/api/articles/:id:get', (connection) => {
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should pass variables on the connection.params from the url', (done) => {
            req.url = '/api/articles/1234/links/daniel';

            events.once('route:/api/articles/:id/links/:item:get', (connection) => {
                assert.isObject(connection);
                assert.strictEqual(connection.params.id, '1234');
                assert.strictEqual(connection.params.item, 'daniel');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('404 routes', () => {
        it('should emit the 404 route event for a 404 route', (done) => {
            req.url = '/about/daniel';

            events.once('error:404', (connection) => {
                assert.isObject(connection);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('static file routes', () => {
        let etag;

        beforeEach(() => {
            etag = '"4b-ah1/iPV1wknehHVYGkU4jQ"';
        });

        it('should emit 404 & missing static events for missing file in sub of public', (done) => {
            req.url = '/static/somefile.js';

            events.required([ 'error:404', 'static:missing' ], (input) => {
                assert.isObject(input[0]);
                assert.isString(input[1]);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should emit 404 event for a non-existant static file in the root of public', (done) => {
            req.url = '/static/somefile.js';

            events.once('error:404', (input) => {
                assert.isObject(input);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return the file for an existing static file with no etag', (done) => {
            req.url = '/static/main.js';

            events.once('response', (input) => {
                assert.isString(input);
                assert.isAbove(input.length, 0);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should have a vary:accept-encoding header for static resources', (done) => {
            const successStatus = 200;

            req.url = '/static/main.js';
            req.method = 'get';
            req.headers['if-none-match'] = '';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                assert.isObject(res.headers);
                assert.strictEqual(res.headers.Vary, 'Accept-Encoding');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return a 304 for a valid etag match', (done) => {
            const unmodStatus = 304;

            req.url = '/static/main.js';
            req.headers['if-none-match'] = etag;

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, unmodStatus);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return just headers if a head request is sent', (done) => {
            const successStatus = 200;

            req.url = '/static/main.js';
            req.method = 'head';
            req.headers['if-none-match'] = '';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                assert.isObject(res.headers);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });

    describe('route.json route', () => {
        it('should return the routes.json file when the router route is requested', (done) => {
            req.url = '/routes';

            events.once('response', (result) => {
                const resultObject = JSON.parse(result);

                assert.isObject(resultObject);
                assert.strictEqual(resultObject['/'][0], routeObject['/'][0]);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });

        });
    });

    describe('compression routes', () => {
        it('should return status code 200 for valid gzip compression', (done) => {
            const successStatus = 200;

            req.method = 'GET';
            req.url = '/static/main.js';
            req.headers['accept-encoding'] = 'gzip';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should have a content-encoding:gzip header for gzip compression', (done) => {
            res.on('finish', () => {
                assert.strictEqual(res.headers['Content-Encoding'], 'gzip');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should serve a file as a response with gzip compression', (done) => {
            events.once('response', (input) => {
                assert.isString(input);
                assert.isAbove(input.length, 0);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should emit served static events for files with gzip compression', (done) => {
            events.once('static:served', (pathname) => {
                assert.strictEqual(pathname, req.url);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should return status code 200 for valid deflate compression', (done) => {
            const successStatus = 200;

            req.headers['accept-encoding'] = 'deflate';

            res.on('finish', () => {
                assert.strictEqual(res.statusCode, successStatus);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should have a content-encoding:deflate header for deflate compression', (done) => {
            res.on('finish', () => {
                assert.strictEqual(res.headers['Content-Encoding'], 'deflate');
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should serve a file as a response with deflate compression', (done) => {
            events.once('response', (input) => {
                assert.isString(input);
                assert.isAbove(input.length, 0);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });

        it('should emit served static events for files with deflate compression', (done) => {
            events.once('static:served', (pathname) => {
                assert.strictEqual(pathname, req.url);
                done();
            });

            process.nextTick(() => {
                routeHandler(req, res);
            });
        });
    });
});
<|endoftext|>