<commit_before>(function() {

    /**
     * Normalizes line endings by removing all \r (carriage return) characters.
     * In IE, newlines in textareas are stored as \r\n instead of just \n, which screws up length calculations.
     * All other browsers automatically remove \r characters when you set the value of the textarea.
     * @returns {string}
     */
    String.prototype.norm = function() {
        return this.replace(/\r/g, '');
    };

    pavlov.specify.extendAssertions({
        isOneOf: function(actual, expected, message) {
            ok(expected.indexOf(actual) !== -1, message);
        }
    });

    pavlov.specify('jQuery Caret Plugin', function() {

        var _e = function(tagName) {
            return document.createElement(tagName);
        };

        var _s = function(obj) {
            return JSON.stringify(obj, null, '    ');
        };

        var _support = {
            normalizesNewlines: (function () {
                var textarea = _e('textarea');
                var text = 'abc\r\ndef';
                textarea.value = text;
                return textarea.value.length === text.length - 1;
            }())
        };

        var $fixture = $('#qunit-fixture');

        var _single = 'abcdefghijklmnop',
            _multi = 'abcdefg\r\nhijklmnop',
            _short = 'abc',
            _long = 'abcdefghijklmnopqrstuvwxyz',
            _empty = '';

        describe('All Plugins', function() {
            var $input, $textarea;

            // befores and afters:

            before(function() {
                $input = $('<input/>').appendTo($fixture);
                $textarea = $('<textarea/>').appendTo($fixture);
            });

            // plugins:

            describe('Caret', function() {
                describe('Get', function() {
                    // Note: Every browser handles automatic caret placement a little differently,
                    // which means our tests need to accommodate both placement strategies
                    // (at the beginning and end of the input/textarea).

                    it("Returns undefined when the jQuery object does not contain an input or textarea element", function() {
                        assert($().caret()).isUndefined();
                        assert($({}).caret()).isUndefined();
                        assert($('<div/>').caret()).isUndefined();
                        assert($([ _e('span'), _e('div'), _e('button') ]).caret()).isUndefined();
                    });

                    describe('<input>', function() {
                        it("Returns the caret position of the first input or textarea element in the jQuery object", function() {
                            var span = _e('span'),
                                div = _e('div'),
                                button = _e('button');

                            // IE throws a hissy fit if the inputs aren't inserted into the DOM before calling
                            // .focus(), .createTextRange(), etc.
                            var input3 = $('<input/>').appendTo($fixture).val('abc').caret(3)[0],
                                input4 = $('<input/>').appendTo($fixture).val('defg').caret(4)[0],
                                input5 = $('<input/>').appendTo($fixture).val('12345').caret(5)[0];

                            assert($([ span, div, button, input3 ]).caret()).equals(3);
                            assert($([ input3, input4, input5 ]).caret()).equals(3);
                            assert($([ input5, input4, input3 ]).caret()).equals(5);
                        });
                    });

                    describe('<input>', function() {
                        it("Returns zero (0) when no value has been set", function() {
                            assert($input.caret()).equals(0);
                        });
                    });

                    describe('<textarea>', function() {
                        it("Returns zero (0) when no value has been set", function() {
                            assert($textarea.caret()).equals(0);
                        });
                    });

                    describe('<input>', function() {
                        it("Returns zero (0) or value.length when a value has been set", function() {
                            // In IE and FF, the caret remains at index 0 the first time a value is set;
                            // the second time a value is set, the caret moves to the end of the input/textarea.
                            assert($input.val(_single).caret()).isOneOf([ 0, _single.length ]);
                            assert($input.val(_single).caret()).isOneOf([ 0, _single.length ]);
                        });
                    });

                    describe('<textarea>', function() {
                        it("Returns zero (0) or value.length when a value has been set", function() {
                            // In IE and FF, the caret remains at index 0 the first time a value is set;
                            // the second time a value is set, the caret moves to the end of the input/textarea.
                            assert($textarea.val(_multi).caret()).isOneOf([ 0, _multi.norm().length ]);
                            assert($textarea.val(_multi).caret()).isOneOf([ 0, _multi.norm().length ]);
                        });
                    });

                    describe('<input>', function() {
                        it("Returns zero (0) or value.length when the input's value changes", function() {
                            assert($input.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($input.val(_long).caret()).isOneOf([ 0, _long.length ]);
                            assert($input.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($input.val(_empty).caret()).isOneOf([ 0, _empty.length ]);
                        });
                    });

                    describe('<textarea>', function() {
                        it("Returns zero (0) or value.length when the textarea's value changes", function() {
                            assert($textarea.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($textarea.val(_long).caret()).isOneOf([ 0, _long.length ]);
                            assert($textarea.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($textarea.val(_empty).caret()).isOneOf([ 0, _empty.length ]);
                        });
                    });
                });

                describe('Set', function() {
                    describe('<input>', function() {
                        var text = _single,
                            len = text.length,
                            mid = Math.floor(len / 2);

                        it("Gets the same position that was set", function() {
                            assert($input.val(text).caret(0).caret()).equals(0);
                            assert($input.val(text).caret(1).caret()).equals(1);
                            assert($input.val(text).caret(mid - 2).caret()).equals(mid - 2);
                            assert($input.val(text).caret(mid - 1).caret()).equals(mid - 1);
                            assert($input.val(text).caret(mid).caret()).equals(mid);
                            assert($input.val(text).caret(mid + 1).caret()).equals(mid + 1);
                            assert($input.val(text).caret(mid + 2).caret()).equals(mid + 2);
                            assert($input.val(text).caret(len - 1).caret()).equals(len - 1);
                            assert($input.val(text).caret(len).caret()).equals(len);
                        });

                        it("Enforces length boundary", function() {
                            assert($input.val(text).caret(len + 1).caret()).equals(len);
                            assert($input.val(text).caret(len + 2).caret()).equals(len);
                        });

                        it("Allows negative position", function() {
                            assert($input.val(text).caret(-1).caret()).equals(len - 1);
                            assert($input.val(text).caret(-2).caret()).equals(len - 2);
                        });

                        it("Converts floating point values to integers", function() {
                            assert($input.val(text).caret(1.5).caret()).equals(1.0);
                            assert($input.val(text).caret(2.5).caret()).equals(2.0);
                        });
                    });

                    describe('<textarea>', function() {
                        var text = _multi,
                            len = text.norm().length,
                            mid = text.indexOf('\n');

                        it("Gets the same position that was set", function() {
                            assert($textarea.val(text).caret(0).caret()).equals(0);
                            assert($textarea.val(text).caret(1).caret()).equals(1);
                            assert($textarea.val(text).caret(mid - 2).caret()).equals(mid - 2);
                            assert($textarea.val(text).caret(mid - 1).caret()).equals(mid - 1);
                            assert($textarea.val(text).caret(mid).caret()).equals(mid);
                            assert($textarea.val(text).caret(mid + 1).caret()).equals(mid + 1);
                            assert($textarea.val(text).caret(mid + 2).caret()).equals(mid + 2);
                            assert($textarea.val(text).caret(len - 1).caret()).equals(len - 1);
                            assert($textarea.val(text).caret(len).caret()).equals(len);
                        });

                        it("Enforces length boundary", function() {
                            assert($textarea.val(text).caret(len + 1).caret()).equals(len);
                            assert($textarea.val(text).caret(len + 2).caret()).equals(len);
                        });

                        it("Allows negative position", function() {
                            assert($textarea.val(text).caret(-1).caret()).equals(len - 1);
                            assert($textarea.val(text).caret(-2).caret()).equals(len - 2);
                        });

                        it("Converts floating point values to integers", function() {
                            assert($textarea.val(text).caret(1.5).caret()).equals(1);
                            assert($textarea.val(text).caret(2.5).caret()).equals(2);
                        });
                    });
                });

                describe('Insert', function() {
                    describe('<input>', function() {
                        it("Prepends text", function() {
                            assert($input.val('abc').caret(0).caret('123').val()).equals('123abc');
                        });

                        it("Appends text", function() {
                            assert($input.val('abc').caret(3).caret('123').val()).equals('abc123');
                        });

                        it("Inserts text", function() {
                            assert($input.val('abcdef').caret(3).caret('123').val()).equals('abc123def');
                        });

                        it("Respects maxlength attribute", function() {
                            $input.attr('maxlength', 5);
                            assert($input.val('abc').caret(0).caret('123').val()).equals('12abc');
                            assert($input.val('abc').caret(3).caret('123').val()).equals('abc12');
                            assert($input.val('abcde').caret(0).caret('123').val()).equals('abcde');
                            assert($input.val('abcde').caret(3).caret('123').val()).equals('abcde');
                            assert($input.val('abcde').caret(5).caret('123').val()).equals('abcde');
                        });
                    });

                    describe('<textarea>', function() {
                        it("Prepends text", function() {
                            assert($textarea.val('abc\ndef').caret(0).caret('123').val()).equals('123abc\ndef');
                        });

                        it("Appends text", function() {
                            assert($textarea.val('abc\ndef').caret(7).caret('123').val()).equals('abc\ndef123');
                        });

                        it("Inserts text", function() {
                            assert($textarea.val('abc\ndef').caret(3).caret('123').val()).equals('abc123\ndef');
                            assert($textarea.val('abc\ndef').caret(4).caret('123').val()).equals('abc\n123def');
                        });

                        it("Respects maxlength attribute", function() {
                            $textarea.attr('maxlength', 9);
                            assert($textarea.val('abc\ndef').caret(0).caret('123').val()).equals('12abc\ndef');
                            assert($textarea.val('abc\ndef').caret(3).caret('123').val()).equals('abc12\ndef');
                            assert($textarea.val('abc\ndef').caret(4).caret('123').val()).equals('abc\n12def');
                            assert($textarea.val('abc\ndef\ng').caret(0).caret('123').val()).equals('abc\ndef\ng');
                            assert($textarea.val('abc\ndef\ng').caret(3).caret('123').val()).equals('abc\ndef\ng');
                            assert($textarea.val('abc\ndef\ng').caret(5).caret('123').val()).equals('abc\ndef\ng');
                        });
                    });
                });
            });

            describe('Range', function() {
                describe('Get', function () {
                    describe('<textarea>', function() {
                        it("Returns the correct range", function() {
                            assert(_s($textarea.val('abc\ndef').range(0, 7).range())).equals(_s({ start: 0, end: 7, length: 7, text: 'abc\ndef' }));
                            assert(_s($textarea.val('abc\ndef').range(3, 4).range())).equals(_s({ start: 3, end: 4, length: 1, text: '\n' }));
                        });
                    });
                });

                describe('Set', function () {
                    describe('<textarea>', function() {
                        it("Accepts a single argument", function() {
                            assert(_s($textarea.val('abc\ndef').range(0).range())).equals(_s($textarea.val('abc\ndef').range(0, 7).range()));
                            assert(_s($textarea.val('abc\ndef').range(3).range())).equals(_s($textarea.val('abc\ndef').range(3, 7).range()));
                        });
                    });

                    // TODO: Test $.fn.range(-3, -8)
                });
            });
        });

    });

}());<commit_msg>Added TODOs to tests.js<commit_after>(function() {

    /**
     * Normalizes line endings by removing all \r (carriage return) characters.
     * In IE, newlines in textareas are stored as \r\n instead of just \n, which screws up length calculations.
     * All other browsers automatically remove \r characters when you set the value of the textarea.
     * @returns {string}
     */
    String.prototype.norm = function() {
        return this.replace(/\r/g, '');
    };

    pavlov.specify.extendAssertions({
        isOneOf: function(actual, expected, message) {
            ok(expected.indexOf(actual) !== -1, message);
        }
    });

    pavlov.specify('jQuery Caret Plugin', function() {

        var _e = function(tagName) {
            return document.createElement(tagName);
        };

        var _s = function(obj) {
            return JSON.stringify(obj, null, '    ');
        };

        var _support = {
            normalizesNewlines: (function () {
                var textarea = _e('textarea');
                var text = 'abc\r\ndef';
                textarea.value = text;
                return textarea.value.length === text.length - 1;
            }())
        };

        var $fixture = $('#qunit-fixture');

        var _single = 'abcdefghijklmnop',
            _multi = 'abcdefg\r\nhijklmnop',
            _short = 'abc',
            _long = 'abcdefghijklmnopqrstuvwxyz',
            _empty = '';

        describe('All Plugins', function() {
            var $input, $textarea;

            // befores and afters:

            before(function() {
                $input = $('<input/>').appendTo($fixture);
                $textarea = $('<textarea/>').appendTo($fixture);
            });

            // plugins:

            describe('Caret', function() {
                describe('Get', function() {
                    // Note: Every browser handles automatic caret placement a little differently,
                    // which means our tests need to accommodate both placement strategies
                    // (at the beginning and end of the input/textarea).

                    it("Returns undefined when the jQuery object does not contain an input or textarea element", function() {
                        assert($().caret()).isUndefined();
                        assert($({}).caret()).isUndefined();
                        assert($('<div/>').caret()).isUndefined();
                        assert($([ _e('span'), _e('div'), _e('button') ]).caret()).isUndefined();
                    });

                    describe('<input>', function() {
                        it("Returns the caret position of the first input or textarea element in the jQuery object", function() {
                            var span = _e('span'),
                                div = _e('div'),
                                button = _e('button');

                            // IE throws a hissy fit if the inputs aren't inserted into the DOM before calling
                            // .focus(), .createTextRange(), etc.
                            var input3 = $('<input/>').appendTo($fixture).val('abc').caret(3)[0],
                                input4 = $('<input/>').appendTo($fixture).val('defg').caret(4)[0],
                                input5 = $('<input/>').appendTo($fixture).val('12345').caret(5)[0];

                            assert($([ span, div, button, input3 ]).caret()).equals(3);
                            assert($([ input3, input4, input5 ]).caret()).equals(3);
                            assert($([ input5, input4, input3 ]).caret()).equals(5);
                        });
                    });

                    describe('<input>', function() {
                        it("Returns zero (0) when no value has been set", function() {
                            assert($input.caret()).equals(0);
                        });
                    });

                    describe('<textarea>', function() {
                        it("Returns zero (0) when no value has been set", function() {
                            assert($textarea.caret()).equals(0);
                        });
                    });

                    describe('<input>', function() {
                        it("Returns zero (0) or value.length when a value has been set", function() {
                            // In IE and FF, the caret remains at index 0 the first time a value is set;
                            // the second time a value is set, the caret moves to the end of the input/textarea.
                            assert($input.val(_single).caret()).isOneOf([ 0, _single.length ]);
                            assert($input.val(_single).caret()).isOneOf([ 0, _single.length ]);
                        });
                    });

                    describe('<textarea>', function() {
                        it("Returns zero (0) or value.length when a value has been set", function() {
                            // In IE and FF, the caret remains at index 0 the first time a value is set;
                            // the second time a value is set, the caret moves to the end of the input/textarea.
                            assert($textarea.val(_multi).caret()).isOneOf([ 0, _multi.norm().length ]);
                            assert($textarea.val(_multi).caret()).isOneOf([ 0, _multi.norm().length ]);
                        });
                    });

                    describe('<input>', function() {
                        it("Returns zero (0) or value.length when the input's value changes", function() {
                            assert($input.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($input.val(_long).caret()).isOneOf([ 0, _long.length ]);
                            assert($input.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($input.val(_empty).caret()).isOneOf([ 0, _empty.length ]);
                        });
                    });

                    describe('<textarea>', function() {
                        it("Returns zero (0) or value.length when the textarea's value changes", function() {
                            assert($textarea.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($textarea.val(_long).caret()).isOneOf([ 0, _long.length ]);
                            assert($textarea.val(_short).caret()).isOneOf([ 0, _short.length ]);
                            assert($textarea.val(_empty).caret()).isOneOf([ 0, _empty.length ]);
                        });
                    });
                });

                describe('Set', function() {
                    describe('<input>', function() {
                        var text = _single,
                            len = text.length,
                            mid = Math.floor(len / 2);

                        it("Gets the same position that was set", function() {
                            assert($input.val(text).caret(0).caret()).equals(0);
                            assert($input.val(text).caret(1).caret()).equals(1);
                            assert($input.val(text).caret(mid - 2).caret()).equals(mid - 2);
                            assert($input.val(text).caret(mid - 1).caret()).equals(mid - 1);
                            assert($input.val(text).caret(mid).caret()).equals(mid);
                            assert($input.val(text).caret(mid + 1).caret()).equals(mid + 1);
                            assert($input.val(text).caret(mid + 2).caret()).equals(mid + 2);
                            assert($input.val(text).caret(len - 1).caret()).equals(len - 1);
                            assert($input.val(text).caret(len).caret()).equals(len);
                        });

                        it("Enforces length boundary", function() {
                            assert($input.val(text).caret(len + 1).caret()).equals(len);
                            assert($input.val(text).caret(len + 2).caret()).equals(len);
                        });

                        it("Allows negative position", function() {
                            assert($input.val(text).caret(-1).caret()).equals(len - 1);
                            assert($input.val(text).caret(-2).caret()).equals(len - 2);
                        });

                        it("Converts floating point values to integers", function() {
                            assert($input.val(text).caret(1.5).caret()).equals(1.0);
                            assert($input.val(text).caret(2.5).caret()).equals(2.0);
                        });
                    });

                    describe('<textarea>', function() {
                        var text = _multi,
                            len = text.norm().length,
                            mid = text.indexOf('\n');

                        it("Gets the same position that was set", function() {
                            assert($textarea.val(text).caret(0).caret()).equals(0);
                            assert($textarea.val(text).caret(1).caret()).equals(1);
                            assert($textarea.val(text).caret(mid - 2).caret()).equals(mid - 2);
                            assert($textarea.val(text).caret(mid - 1).caret()).equals(mid - 1);
                            assert($textarea.val(text).caret(mid).caret()).equals(mid);
                            assert($textarea.val(text).caret(mid + 1).caret()).equals(mid + 1);
                            assert($textarea.val(text).caret(mid + 2).caret()).equals(mid + 2);
                            assert($textarea.val(text).caret(len - 1).caret()).equals(len - 1);
                            assert($textarea.val(text).caret(len).caret()).equals(len);
                        });

                        it("Enforces length boundary", function() {
                            assert($textarea.val(text).caret(len + 1).caret()).equals(len);
                            assert($textarea.val(text).caret(len + 2).caret()).equals(len);
                        });

                        it("Allows negative position", function() {
                            assert($textarea.val(text).caret(-1).caret()).equals(len - 1);
                            assert($textarea.val(text).caret(-2).caret()).equals(len - 2);
                        });

                        it("Converts floating point values to integers", function() {
                            assert($textarea.val(text).caret(1.5).caret()).equals(1);
                            assert($textarea.val(text).caret(2.5).caret()).equals(2);
                        });
                    });
                });

                describe('Insert', function() {
                    describe('<input>', function() {
                        it("Prepends text", function() {
                            assert($input.val('abc').caret(0).caret('123').val()).equals('123abc');
                        });

                        it("Appends text", function() {
                            assert($input.val('abc').caret(3).caret('123').val()).equals('abc123');
                        });

                        it("Inserts text", function() {
                            assert($input.val('abcdef').caret(3).caret('123').val()).equals('abc123def');
                        });

                        it("Respects maxlength attribute", function() {
                            $input.attr('maxlength', 5);
                            assert($input.val('abc').caret(0).caret('123').val()).equals('12abc');
                            assert($input.val('abc').caret(3).caret('123').val()).equals('abc12');
                            assert($input.val('abcde').caret(0).caret('123').val()).equals('abcde');
                            assert($input.val('abcde').caret(3).caret('123').val()).equals('abcde');
                            assert($input.val('abcde').caret(5).caret('123').val()).equals('abcde');
                        });

                        it("TODO: Test caret position AFTER insertion");
                    });

                    describe('<textarea>', function() {
                        it("Prepends text", function() {
                            assert($textarea.val('abc\ndef').caret(0).caret('123').val()).equals('123abc\ndef');
                        });

                        it("Appends text", function() {
                            assert($textarea.val('abc\ndef').caret(7).caret('123').val()).equals('abc\ndef123');
                        });

                        it("Inserts text", function() {
                            assert($textarea.val('abc\ndef').caret(3).caret('123').val()).equals('abc123\ndef');
                            assert($textarea.val('abc\ndef').caret(4).caret('123').val()).equals('abc\n123def');
                        });

                        it("Respects maxlength attribute", function() {
                            $textarea.attr('maxlength', 9);
                            assert($textarea.val('abc\ndef').caret(0).caret('123').val()).equals('12abc\ndef');
                            assert($textarea.val('abc\ndef').caret(3).caret('123').val()).equals('abc12\ndef');
                            assert($textarea.val('abc\ndef').caret(4).caret('123').val()).equals('abc\n12def');
                            assert($textarea.val('abc\ndef\ng').caret(0).caret('123').val()).equals('abc\ndef\ng');
                            assert($textarea.val('abc\ndef\ng').caret(3).caret('123').val()).equals('abc\ndef\ng');
                            assert($textarea.val('abc\ndef\ng').caret(5).caret('123').val()).equals('abc\ndef\ng');
                        });

                        it("TODO: Test caret position AFTER insertion");
                    });
                });
            });

            describe('Range', function() {
                describe('Get', function () {
                    describe('<textarea>', function() {
                        it("Returns the correct range", function() {
                            assert(_s($textarea.val('abc\ndef').range(0, 7).range())).equals(_s({ start: 0, end: 7, length: 7, text: 'abc\ndef' }));
                            assert(_s($textarea.val('abc\ndef').range(3, 4).range())).equals(_s({ start: 3, end: 4, length: 1, text: '\n' }));
                        });
                    });
                });

                describe('Set', function () {
                    describe('<textarea>', function() {
                        it("Accepts a single argument", function() {
                            assert(_s($textarea.val('abc\ndef').range(0).range())).equals(_s($textarea.val('abc\ndef').range(0, 7).range()));
                            assert(_s($textarea.val('abc\ndef').range(3).range())).equals(_s($textarea.val('abc\ndef').range(3, 7).range()));
                        });
                    });

                    // TODO: Test $.fn.range(-3, -8)
                });

                it("TODO: Test range positions AFTER replacement/insertion");
            });
        });

    });

}());<|endoftext|>


<commit_before>module.exports = function (err) {
    setTimeout(function () {
        throw err;
    });
};
<commit_msg>opt: throw error<commit_after>module.exports = function (err) {
    setTimeout(function () {
        if (err instanceof Error)
            throw err
        else
            throw JSON.stringify(err, null, 4)
    })
}
<|endoftext|>


<commit_before>(function(window, document){

  function throttle(fn, minDelay) {
    var lastCall = 0;
    return function() {
      var now = +new Date;
      if (now - lastCall < minDelay) {
        return;
      }
      lastCall = now;
      // we do not return anything as
      // https://github.com/documentcloud/underscore/issues/387
      fn.apply(this, arguments);
    }
  }

  // cross browser event handling
  function addEvent( el, type, fn ) {
    if (el.attachEvent) {
      el.attachEvent && el.attachEvent( 'on' + type, fn );
    } else {
      el.addEventListener( type, fn, false );
    }
  }

  // cross browser event handling
  function removeEvent( el, type, fn ) {
    if (el.detachEvent) {
      el.detachEvent && el.detachEvent( 'on' + type, fn );
    } else {
      el.removeEventListener( type, fn, false );
    }
  }

  // glocal variables
  var
    lazyAttr = 'data-src',
    offset = 200,
    winH,

    // cross browser window height
    getWindowHeight = throttle(function getWindowHeight() {
      winH = window.innerHeight ||
        (document.documentElement && document.documentElement.clientHeight) ||
        (document.body && document.body.clientHeight) ||
        10000;
    }, 30),

    checkImages = throttle(function checkImages() {
      var imgs = document.getElementsByTagName('img'),
        last = imgs.length,
        current;

      for (current = 0; current < last; current++) {
        showIfVisible(imgs[current]);
      }
    }, 30);

  function showIfVisible(el) {
    if (el.getAttribute(lazyAttr) !== null && el.getBoundingClientRect().top < winH + offset) {
      el.src = el.getAttribute(lazyAttr);
      el.removeAttribute(lazyAttr);
    }
  }

  getWindowHeight();
  addEvent(window, 'resize', getWindowHeight);
  addEvent(window, 'scroll', checkImages);

})(this, document)
<commit_msg>Add window.fstrz variable #182325<commit_after>(function(window, document){

  window.fstrz = true;

  function throttle(fn, minDelay) {
    var lastCall = 0;
    return function() {
      var now = +new Date;
      if (now - lastCall < minDelay) {
        return;
      }
      lastCall = now;
      // we do not return anything as
      // https://github.com/documentcloud/underscore/issues/387
      fn.apply(this, arguments);
    }
  }

  // cross browser event handling
  function addEvent( el, type, fn ) {
    if (el.attachEvent) {
      el.attachEvent && el.attachEvent( 'on' + type, fn );
    } else {
      el.addEventListener( type, fn, false );
    }
  }

  // cross browser event handling
  function removeEvent( el, type, fn ) {
    if (el.detachEvent) {
      el.detachEvent && el.detachEvent( 'on' + type, fn );
    } else {
      el.removeEventListener( type, fn, false );
    }
  }

  // glocal variables
  var
    lazyAttr = 'data-src',
    offset = 200,
    winH,

    // cross browser window height
    getWindowHeight = throttle(function getWindowHeight() {
      winH = window.innerHeight ||
        (document.documentElement && document.documentElement.clientHeight) ||
        (document.body && document.body.clientHeight) ||
        10000;
    }, 30),

    checkImages = throttle(function checkImages() {
      var imgs = document.getElementsByTagName('img'),
        last = imgs.length,
        current;

      for (current = 0; current < last; current++) {
        showIfVisible(imgs[current]);
      }
    }, 30);

  function showIfVisible(el) {
    if (el.getAttribute(lazyAttr) !== null && el.getBoundingClientRect().top < winH + offset) {
      el.src = el.getAttribute(lazyAttr);
      el.removeAttribute(lazyAttr);
    }
  }

  getWindowHeight();
  addEvent(window, 'resize', getWindowHeight);
  addEvent(window, 'scroll', checkImages);

})(this, document)
<|endoftext|>


<commit_before>;(function() {
'use strict';

angular.module('gebo-client-token', ['ngRoute', 'ngResource'])
  .factory('Token', function ($http, $q, $window, $rootScope, $resource, $filter) {

    /**
     * This is the data returned on verification.
     */
    var _agent = {};

    /**
     *  This response type must be passed to the authorization endpoint using
     *  the implicit grant flow (4.2.1 of RFC 6749).
     */
    var RESPONSE_TYPE = 'token';

    /**
     * Create a special object for endpoint fields that are required and missing.
     * If any endpoint items still contain it when Token is used, raise an error.
     */
    var REQUIRED_AND_MISSING = {};

    /**
     * Default endpoint fields. These need to be set somewhere else.
     */
    var _endpoint = {
      gebo: REQUIRED_AND_MISSING,
      redirect: REQUIRED_AND_MISSING,
      clientId: REQUIRED_AND_MISSING,
      clientName: REQUIRED_AND_MISSING,
      authorize: '/dialog/authorize',
      verify: '/verify',
      perform: '/perform',
      send: '/send',
      localStorageName: REQUIRED_AND_MISSING,
      scopes: ''
    };

    /**
     * Get the token request parameters
     *
     * @throws Error
     */
    var _getParams = function() {
        var requiredAndMissing = [];

        angular.forEach(_endpoint, function(value, key) {
            if (value === REQUIRED_AND_MISSING || value === undefined) {
              requiredAndMissing.push(key);
            }
          });

        if (requiredAndMissing.length) {
          throw new Error('Token is insufficiently configured. Please ' +
                          'configure the following options: ' +
                          requiredAndMissing.join(', '));
        }

        return {
          response_type: RESPONSE_TYPE,
          client_id: _endpoint.clientId,
          client_name: _endpoint.clientName,
          redirect_uri: _endpoint.redirect,
          scope: _endpoint.scopes
        };
      };

    /**
     * Set the configuration options
     */
    var _setEndpoints = function(endpoint) {
        _endpoint = angular.extend(_endpoint, endpoint);
      };

    // TODO: get/set might want to support expiration to reauthenticate
    // TODO: check for localStorage support and otherwise perhaps use other
    // methods of storing data (e.g. cookie)

    /**
     * Returns the stored access token.
     *
     * @returns {string} The access token.
     */
    var _get = function() {
        return localStorage.getItem(_endpoint.localStorageName);
      };

    /**
     * Persist the access token so that it can be retrieved later by.
     *
     * @param accessToken
     */
    var _set = function(accessToken) {
        localStorage.setItem(_endpoint.localStorageName, accessToken);
      };

    /**
     * Remove token from local storage and clear
     * authentication data
     */
    var _clear = function() {
        _agent = {};
        localStorage.removeItem(_endpoint.localStorageName);
      };

    /**
     * Verifies an access token asynchronously.
     *
     * @param extraParams An access token received from the authorization server.
     * @param popupOptions Settings for the display of the popup.
     *
     * @returns {Promise} Promise that will be resolved when the authorization
     *                    server has verified that thetoken is valid, and we've
     *                    verified that the token is passed back has audience
     *                    that matches our client ID (to prevent the Confused
     *                    Deputy Problem).
     *
     *  If there's an error verifying the token, the promise is rejected with an
     *  object identifying the `name` error in the name member. The `name` can
     *  be either:
     *
     *    - `invalid_audience`: The audience didn't match our client ID.
     *    - `error_response`: The server responded with an error, typically
     *                        because the token was invalid.  In this
     *                        case, the callback parameters to `error` callback
     *                        on `$http` are available in the object (`data`,
     *                        `status`, `headers`, `endpoint`).
     */
    var _getTokenByPopup = function(extraParams, popupOptions) {
        popupOptions = angular.extend({
            name: 'AuthPopup',
            openParams: {
                width: 650,
                height: 300,
                resizable: true,
                scrollbars: true,
                status: true
              }
            }, popupOptions);

        var deferred = $q.defer(),
            params = angular.extend(_getParams(), extraParams),
            url = _getEndpointUri('authorize') + '?' + _objectToQueryString(params);

        var formatPopupOptions = function(options) {
            var pairs = [];
            angular.forEach(options, function(value, key) {
                if (value || value === 0) {
                  value = value === true ? 'yes' : value;
                  pairs.push(key + '=' + value);
                }
              });

            return pairs.join(',');
          };

        var popup = window.open(
            url,
            popupOptions.name,
            formatPopupOptions(popupOptions.openParams));

        // TODO: binding occurs for each reauthentication,
        // leading to leaks for long-running apps.

        angular.element($window).bind('message', function(event) {
            if (event.source === popup && event.origin === window.location.origin) {
              $rootScope.$apply(function() {
                if (event.data.access_token) {
                  deferred.resolve(event.data);
                } else {
                  deferred.reject(event.data);
                }
              });
            }
          });

          // TODO: reject deferred if the popup was closed without
          // a message being delivered + maybe offer a timeout

        return deferred.promise;
      };

    /**
     * Given an flat object, return an URL-friendly query string.  Note
     * that for a given object, the return value may be.
     *
     * @example
     *

     *    // returns 'color=red&size=large'
     *    _objectToQueryString({color: 'red', size: 'large'})
     *

     *
     * @param {Object} A flat object containing keys for a query string.
     *
     * @returns {string} An URL-friendly query string.
     */
    var _objectToQueryString = function(obj) {
      var str = [];
      angular.forEach(obj, function(value, key) {
        str.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
      });
      return str.join('&');
    };

    /**
     * Verify the user is still authenticated
     *
     * @param string
     *
     * @return promise
     */
    var _verify = function(accessToken) {
        var deferred = $q.defer();

        $http.get(_getEndpointUri('verify') + '?access_token=' + accessToken).
                success(
                    function(response) {
                        _agent = response;
                        deferred.resolve(response);
                      }).
                error(
                    function(obj, err) {
                        deferred.reject(err);
                      });

        return deferred.promise;
      };

    /**
     * Attempt to perform an action on a resource
     *
     * @param Object
     */
    function _perform(content) {
        var deferred = $q.defer();

        // A perform message can either come as
        // a FormData object or plain JSON
        if (content instanceof FormData) {
          content.append('access_token', _get());

          $http.defaults.headers.common['Content-Type'] = undefined;
          $http.defaults.transformRequest = angular.identity;
        }
        else {
          content.access_token = _get();
          $http.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded';
        }
        $http.post(_getEndpointUri('perform'), content).
              success(function(response) {
                  deferred.resolve(response);
                }).
              error(function(obj, err) {
                  deferred.reject({ code: err, message: obj });
                });
        return deferred.promise;
      };

    /**
     * Encode embedded JSON
     *
     * Not currently using this, but it may be useful soon
     *
     * From: http://blog.tryfinally.co.za/2012/12/form-url-encoded-post-with-angularjs.html
     *
     * @param string
     *
     * @return string
     */
    function _formEncode(obj) {
        var jsonString = '';
        for (var key in obj) {
          if (jsonString.length !== 0) {
            jsonString += '&';
          }
          jsonString += key + '=' + $filter('json')(obj[key]);
        }
        return jsonString;
      }

    /**
     * Get an endpoint URI
     *
     * @param string
     *
     * @return string
     */
    function _getEndpointUri(endpoint) {
        return _endpoint.gebo + _endpoint[endpoint];
      }

    /**
     * Send a message
     *
     * @param Object
     *
     * @return promise
     */
    function _send(message) {
        var deferred = $q.defer();

        message.access_token = _get();

        $http.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded';
        $http.post(_getEndpointUri('send'), message).
                success(
                    function(response) {
                        deferred.resolve(response);
                      }).
                error(
                    function(obj, err) {
                        deferred.reject(err);
                      });

        return deferred.promise;
      }

    return {
      clear: _clear,
      agent: function() {
              return _agent;
            },
      formEncode: _formEncode,
      get: _get,
      getEndpoints: function() {
              return _endpoint;
            },
      getEndpointUri: _getEndpointUri,
      getParams: _getParams,
      getTokenByPopup: _getTokenByPopup,
      objectToQueryString: _objectToQueryString,
      perform: _perform,
      verify: _verify,
//      request: _request,
      send: _send,
      set: _set,
      setEndpoints: _setEndpoints,
    };
  });
}());
<commit_msg>Reverse previous DRYing steps<commit_after>;(function() {
'use strict';

angular.module('gebo-client-token', ['ngRoute', 'ngResource'])
  .factory('Token', function ($http, $q, $window, $rootScope, $resource, $filter) {

    /**
     * This is the data returned on verification.
     */
    var _agent = {};

    /**
     *  This response type must be passed to the authorization endpoint using
     *  the implicit grant flow (4.2.1 of RFC 6749).
     */
    var RESPONSE_TYPE = 'token';

    /**
     * Create a special object for endpoint fields that are required and missing.
     * If any endpoint items still contain it when Token is used, raise an error.
     */
    var REQUIRED_AND_MISSING = {};

    /**
     * Default endpoint fields. These need to be set somewhere else.
     */
    var _endpoint = {
      gebo: REQUIRED_AND_MISSING,
      redirect: REQUIRED_AND_MISSING,
      clientId: REQUIRED_AND_MISSING,
      clientName: REQUIRED_AND_MISSING,
      authorize: '/dialog/authorize',
      verify: '/verify',
      perform: '/perform',
      send: '/send',
      localStorageName: REQUIRED_AND_MISSING,
      scopes: ''
    };

    /**
     * Get the token request parameters
     *
     * @throws Error
     */
    var _getParams = function() {
        var requiredAndMissing = [];

        angular.forEach(_endpoint, function(value, key) {
            if (value === REQUIRED_AND_MISSING || value === undefined) {
              requiredAndMissing.push(key);
            }
          });

        if (requiredAndMissing.length) {
          throw new Error('Token is insufficiently configured. Please ' +
                          'configure the following options: ' +
                          requiredAndMissing.join(', '));
        }

        return {
          response_type: RESPONSE_TYPE,
          client_id: _endpoint.clientId,
          client_name: _endpoint.clientName,
          redirect_uri: _endpoint.redirect,
          scope: _endpoint.scopes
        };
      };

    /**
     * Set the configuration options
     */
    var _setEndpoints = function(endpoint) {
        _endpoint = angular.extend(_endpoint, endpoint);
      };

    // TODO: get/set might want to support expiration to reauthenticate
    // TODO: check for localStorage support and otherwise perhaps use other
    // methods of storing data (e.g. cookie)

    /**
     * Returns the stored access token.
     *
     * @returns {string} The access token.
     */
    var _get = function() {
        return localStorage.getItem(_endpoint.localStorageName);
      };

    /**
     * Persist the access token so that it can be retrieved later by.
     *
     * @param accessToken
     */
    var _set = function(accessToken) {
        localStorage.setItem(_endpoint.localStorageName, accessToken);
      };

    /**
     * Remove token from local storage and clear
     * authentication data
     */
    var _clear = function() {
        _agent = {};
        localStorage.removeItem(_endpoint.localStorageName);
      };

    /**
     * Verifies an access token asynchronously.
     *
     * @param extraParams An access token received from the authorization server.
     * @param popupOptions Settings for the display of the popup.
     *
     * @returns {Promise} Promise that will be resolved when the authorization
     *                    server has verified that thetoken is valid, and we've
     *                    verified that the token is passed back has audience
     *                    that matches our client ID (to prevent the Confused
     *                    Deputy Problem).
     *
     *  If there's an error verifying the token, the promise is rejected with an
     *  object identifying the `name` error in the name member. The `name` can
     *  be either:
     *
     *    - `invalid_audience`: The audience didn't match our client ID.
     *    - `error_response`: The server responded with an error, typically
     *                        because the token was invalid.  In this
     *                        case, the callback parameters to `error` callback
     *                        on `$http` are available in the object (`data`,
     *                        `status`, `headers`, `endpoint`).
     */
    var _getTokenByPopup = function(extraParams, popupOptions) {
        popupOptions = angular.extend({
            name: 'AuthPopup',
            openParams: {
                width: 650,
                height: 300,
                resizable: true,
                scrollbars: true,
                status: true
              }
            }, popupOptions);

        var deferred = $q.defer(),
            params = angular.extend(_getParams(), extraParams),
            url = _getEndpointUri('authorize') + '?' + _objectToQueryString(params);

        var formatPopupOptions = function(options) {
            var pairs = [];
            angular.forEach(options, function(value, key) {
                if (value || value === 0) {
                  value = value === true ? 'yes' : value;
                  pairs.push(key + '=' + value);
                }
              });

            return pairs.join(',');
          };

        var popup = window.open(
            url,
            popupOptions.name,
            formatPopupOptions(popupOptions.openParams));

        // TODO: binding occurs for each reauthentication,
        // leading to leaks for long-running apps.

        angular.element($window).bind('message', function(event) {
            if (event.source === popup && event.origin === window.location.origin) {
              $rootScope.$apply(function() {
                if (event.data.access_token) {
                  deferred.resolve(event.data);
                } else {
                  deferred.reject(event.data);
                }
              });
            }
          });

          // TODO: reject deferred if the popup was closed without
          // a message being delivered + maybe offer a timeout

        return deferred.promise;
      };

    /**
     * Given an flat object, return an URL-friendly query string.  Note
     * that for a given object, the return value may be.
     *
     * @example
     *

     *    // returns 'color=red&size=large'
     *    _objectToQueryString({color: 'red', size: 'large'})
     *

     *
     * @param {Object} A flat object containing keys for a query string.
     *
     * @returns {string} An URL-friendly query string.
     */
    var _objectToQueryString = function(obj) {
      var str = [];
      angular.forEach(obj, function(value, key) {
        str.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
      });
      return str.join('&');
    };

    /**
     * Verify the user is still authenticated
     *
     * @param string
     *
     * @return promise
     */
    var _verify = function(accessToken) {
        var deferred = $q.defer();

        $http.get(_getEndpointUri('verify') + '?access_token=' + accessToken).
                success(
                    function(response) {
                        _agent = response;
                        deferred.resolve(response);
                      }).
                error(
                    function(obj, err) {
                        deferred.reject(err);
                      });

        return deferred.promise;
      };

    /**
     * Attempt to perform an action on a resource
     *
     * You'd think this would be easy to DRY out...
     *
     * @param Object
     */
    function _perform(content) {
        var deferred = $q.defer();

        // A perform message can either come as
        // a FormData object or plain JSON
        if (content instanceof FormData) {
          content.append('access_token', _get());

          $http.post(_getEndpointUri('perform'), content, {
                  headers: { 'Content-Type': undefined },
                  transformRequest: angular.identity }).
                success(function(response) {
                    deferred.resolve(response);
                  }).
                error(function(obj, err) {
                    deferred.reject({ code: err, message: obj });
                  });
        }
        else {
          content.access_token = _get();
          $http.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded';

          $http.post(_getEndpointUri('perform'), content).
                success(function(response) {
                    deferred.resolve(response);
                  }).
                error(function(obj, err) {
                    deferred.reject({ code: err, message: obj });
                  });
        }

        return deferred.promise;
      };

    /**
     * Encode embedded JSON
     *
     * Not currently using this, but it may be useful soon
     *
     * From: http://blog.tryfinally.co.za/2012/12/form-url-encoded-post-with-angularjs.html
     *
     * @param string
     *
     * @return string
     */
    function _formEncode(obj) {
        var jsonString = '';
        for (var key in obj) {
          if (jsonString.length !== 0) {
            jsonString += '&';
          }
          jsonString += key + '=' + $filter('json')(obj[key]);
        }
        return jsonString;
      }

    /**
     * Get an endpoint URI
     *
     * @param string
     *
     * @return string
     */
    function _getEndpointUri(endpoint) {
        return _endpoint.gebo + _endpoint[endpoint];
      }

    /**
     * Send a message
     *
     * @param Object
     *
     * @return promise
     */
    function _send(message) {
        var deferred = $q.defer();

        message.access_token = _get();

        $http.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded';
        $http.post(_getEndpointUri('send'), message).
                success(
                    function(response) {
                        deferred.resolve(response);
                      }).
                error(
                    function(obj, err) {
                        deferred.reject(err);
                      });

        return deferred.promise;
      }

    return {
      clear: _clear,
      agent: function() {
              return _agent;
            },
      formEncode: _formEncode,
      get: _get,
      getEndpoints: function() {
              return _endpoint;
            },
      getEndpointUri: _getEndpointUri,
      getParams: _getParams,
      getTokenByPopup: _getTokenByPopup,
      objectToQueryString: _objectToQueryString,
      perform: _perform,
      verify: _verify,
//      request: _request,
      send: _send,
      set: _set,
      setEndpoints: _setEndpoints,
    };
  });
}());
<|endoftext|>


<commit_before>var http = require('http'),
    url = require('url'),
    fs = require('fs'),
    ejs = require('ejs'),
    path = require('path'),
    exec = require('child_process').exec,
    util = require('util');
//var querystring = require('querystring');

var mime_types = {}
var routes = []
//--------------------------------------------------
var Route = function(){

    this.get = new Handler();
    this.post = new Handler();
    return this;
}
//--------------------------------------------------
var Handler = function(){
    return this;
}
//--------------------------------------------------
Handler.prototype.html = function(template_path){
    //load template
    var t = this;
    fs.readFile(template_path, function (err, data) {
          if (err) throw err;
          t.compiled = ejs.compile(String(data));
    });
    return this;
}
//===================================================
Handler.prototype.static = function(base_dir){

    //----------------------------------------------------
    var send_stream = function(fs_path,req,res,headers) {

        fs.stat(fs_path,function(err,stats){

            if(err){
                res.writeHead(404);
                res.end("404 - not found.");
                return;

            }
            var ins = util.inspect(stats);
            var size = ins.match(/size:\s*(\d+)/)[1];
            headers['Content-Length'] = size;

           var flags = {};
           console.log(req.headers);
           range = req.headers['range'];

           if(range){
                var match = range.match(/^bytes\s*=\s*(\d+)-(\d*)/);
                if(match){
                    var start = parseInt(match[1]);
                    var end = match[2].length > 0 ? parseInt(match[2]) : parseInt(size) -1;
                    headers["Content-Range"] =  'bytes %start-%end/%length'.replace("%start",start).replace("%end",end).replace("%length",size);
                    res.writeHead(206,headers);
                    flags["start"] = start;
                    flags["end"] = end;
                }
                else{
                    res.writeHead(416,headers);
                }
            }
            else
                res.writeHead(200,headers);
            /*fs.readFile(fs_path, function (err, data) {
              if (err)
                throw err;

                res.end(data);
            });*/
            var fstream = fs.createReadStream(fs_path,flags);
            fstream.pipe(res);

        });

        /*}
            kv = range.split("=");
            if(!kv[1])
        }*/
    }
    //----------------------------------------------------
    var send_ogg= function(path,req,res,headers,flags){

       var child = exec("ogginfo %s | grep 'Playback length'".replace("%s",path),
                  function (error, stdout, stderr) {
                      if(error)
                            throw error;

                    var lens = stdout.trim().split(":");
                    var MINUTES = 1, SECONDS = 2;
                    var duration = parseFloat(lens[MINUTES])*60 + parseFloat(lens[SECONDS]);
                    headers['X-Content-Duration'] = String(duration);
                    send_stream(path,req,res,headers);
            });
    }
    //----------------------------------------------------

    if(typeof(base_dir)==="undefined")
        base_dir = "";

    this.send_static = function(file_path,req,res){

        var ext = path.extname(file_path).substring(1),
            mime_type = mime_types[ext],
            fs_path = path.join(path.resolve(base_dir),file_path),
            headers = {'Accept-Ranges': 'bytes','Content-Type':mime_type};

        if(Ys.ogg_header_support && headers["Content-Type"] && headers["Content-Type"].match(/^\w+\/ogg$/)){
            send_ogg(fs_path,req,res,headers);
            return;
        }

        send_stream(fs_path,req,res,headers);
    }
}
//===================================================
var Ys = exports.Ys = function(url) {

    var idx = routes.indexOf(url);
    if(idx===-1){
        routes.push([url,new Route()]);
        idx = routes.length - 1;
    }

    return routes[idx][1]

}
//--------------------------------------------------
var jsonify = function(object){
    this.end(JSON.stringify(object));
}
//--------------------------------------------------
var htmlify = function(compiled_template){

    return function(object){
        this.end(compiled_template(object));
    }
}
//--------------------------------------------------
var PATH_REGEXP = 0, HANDLERS = 1;
var handle_request = function(req,res){

    var pathname = url.parse(req.url).pathname;
    for(var i=0; i < routes.length; i++){
        var regexp = RegExp(routes[i][PATH_REGEXP]);
        var route = routes[i];
        var match = regexp.exec(pathname);
        if(!match)
            continue;

        if(typeof(route[HANDLERS]["redirect"]) === "string"){
            pathname = route[HANDLERS]["redirect"].replace("$1",match[1]);
            res.writeHead(301,{"Location":pathname});
            res.end();
            return;
        }

        if(typeof(route[HANDLERS]["rewrite"]) === "string"){
            pathname = route[HANDLERS]["rewrite"].replace("$1",match[1]);
            continue;
        }

        if(typeof(route[HANDLERS][req.method.toLowerCase()])==="undefined")
            continue;

        var handler = route[HANDLERS][req.method.toLowerCase()];
        if(typeof(handler)==="function"){
            handler(req,res);
            return;
        }

        if(typeof(handler)==="object"){

            if("send_static" in handler){
                handler.send_static(pathname,req,res);
                return;
            }

            if("json" in handler){
                res.writeHead(200, {'Content-Type': 'application/json'});
                res.returnObject = jsonify;
                handler.json(req,res);
                return;
            }

            if("html" in handler){

                res.writeHead(200, {'Content-Type': 'text/html'});
                if("args" in handler){//actual template
                    res.returnObject = htmlify(handler.compiled);
                    handler.args(req,res);
                }
                else
                    res.end(htmlify(handler.compiled)());
            }

            return;
        }

    }

    throw new Error(pathname +" >> No mapping for this path");
}
//--------------------------------------------------
Ys.run = function(port,host){

    if(!port)
        port = 8780;

    if(!host)
        host= "127.0.0.1";

    var mimes_raw  = fs.readFileSync('/etc/mime.types','utf-8').split('\n')
    for(var i=0; i<mimes_raw.length; i++){
        var next = mimes_raw[i].split(/\s+/g)
        if(next && next.length >= 2)
            for(var j=1; j < next.length; j++)
                mime_types[next[j]] = next[0];
    }

    //correction for some types
    //mime_types["mp3"] = "audio/mp3";
    process.on('uncaughtException', function (err) {
            var str = err.stack;
            console.log(str);
            //res.end(str);
    });

    http.createServer(function (req, res) {

        try{
            handle_request(req,res);
        }
        catch(e){
            var str = e.stack;
            console.log(str);
            res.end(str);
        }

    }).listen(port,host);
    console.log('Server running at '+host+':'+port+'/');
}
//--------------------------------------------------
<commit_msg>fixes<commit_after>var http = require('http'),
    url = require('url'),
    fs = require('fs'),
    ejs = require('ejs'),
    path = require('path'),
    exec = require('child_process').exec,
    util = require('util');
//var querystring = require('querystring');

var mime_types = {}
var routes = []
//--------------------------------------------------
var Route = function(){

    this.get = new Handler();
    this.post = new Handler();
    return this;
}
//--------------------------------------------------
var Handler = function(){
    return this;
}
//--------------------------------------------------
Handler.prototype.html = function(template_path){
    //load template
    var t = this;
    fs.readFile(template_path, function (err, data) {
          if (err) throw err;
          t.compiled = ejs.compile(String(data));
    });
    return this;
}
//===================================================
Handler.prototype.static = function(base_dir){

    //----------------------------------------------------
    var send_stream = function(fs_path,req,res,headers) {

        fs.stat(fs_path,function(err,stats){

            if(err){
                res.writeHead(404);
                res.end("404 - not found.");
                return;

            }
            var ins = util.inspect(stats);
            var size = ins.match(/size:\s*(\d+)/)[1];
            headers['Content-Length'] = size;

           var flags = {};
           //console.log(req.headers);
           range = req.headers['range'];

           if(range){
                var match = range.match(/^bytes\s*=\s*(\d+)-(\d*)/);
                if(match){
                    var start = parseInt(match[1]);
                    var end = match[2].length > 0 ? parseInt(match[2]) : parseInt(size) -1;
                    headers["Content-Range"] =  'bytes %start-%end/%length'.replace("%start",start).replace("%end",end).replace("%length",size);
                    res.writeHead(206,headers);
                    flags["start"] = start;
                    flags["end"] = end;
                }
                else{
                    res.writeHead(416,headers);
                }
            }
            else
                res.writeHead(200,headers);
            /*fs.readFile(fs_path, function (err, data) {
              if (err)
                throw err;

                res.end(data);
            });*/
            var fstream = fs.createReadStream(fs_path,flags);
            fstream.pipe(res);

        });

        /*}
            kv = range.split("=");
            if(!kv[1])
        }*/
    }
    //----------------------------------------------------
    var send_ogg= function(path,req,res,headers,flags){

       var child = exec("ogginfo %s | grep 'Playback length'".replace("%s",path),
                  function (error, stdout, stderr) {
                      if(error)
                            throw error;

                    var lens = stdout.trim().split(":");
                    var MINUTES = 1, SECONDS = 2;
                    var duration = parseFloat(lens[MINUTES])*60 + parseFloat(lens[SECONDS]);
                    headers['X-Content-Duration'] = String(duration);
                    send_stream(path,req,res,headers);
            });
    }
    //----------------------------------------------------

    if(typeof(base_dir)==="undefined")
        base_dir = "";

    this.send_static = function(file_path,req,res){

        var ext = path.extname(file_path).substring(1),
            mime_type = mime_types[ext],
            fs_path = path.join(path.resolve(base_dir),file_path),
            headers = {'Accept-Ranges': 'bytes','Content-Type':mime_type};

        if(Ys.ogg_header_support && headers["Content-Type"] && headers["Content-Type"].match(/^\w+\/ogg$/)){
            send_ogg(fs_path,req,res,headers);
            return;
        }

        send_stream(fs_path,req,res,headers);
    }
}
//===================================================
var Ys = exports.Ys = function(url) {

    var idx = routes.indexOf(url);
    if(idx===-1){
        routes.push([url,new Route()]);
        idx = routes.length - 1;
    }

    return routes[idx][1]

}
//--------------------------------------------------
var jsonify = function(object){
    this.end(JSON.stringify(object));
}
//--------------------------------------------------
var htmlify = function(compiled_template){

    return function(object){
        this.end(compiled_template(object));
    }
}
//--------------------------------------------------
var PATH_REGEXP = 0, HANDLERS = 1;
var handle_request = function(req,res){

    var pathname = url.parse(req.url).pathname;
    for(var i=0; i < routes.length; i++){
        var regexp = RegExp(routes[i][PATH_REGEXP]);
        var route = routes[i];
        var match = regexp.exec(pathname);
        if(!match)
            continue;

        if(typeof(route[HANDLERS]["redirect"]) === "string"){
            pathname = route[HANDLERS]["redirect"].replace("$1",match[1]);
            res.writeHead(301,{"Location":pathname});
            res.end();
            return;
        }

        if(typeof(route[HANDLERS]["rewrite"]) === "string"){
            pathname = route[HANDLERS]["rewrite"].replace("$1",match[1]);
            continue;
        }

        if(typeof(route[HANDLERS][req.method.toLowerCase()])==="undefined")
            continue;

        var handler = route[HANDLERS][req.method.toLowerCase()];
        if(typeof(handler)==="function"){
            handler(req,res);
            return;
        }

        if(typeof(handler)==="object"){

            if("send_static" in handler){
                handler.send_static(pathname,req,res);
                return;
            }

            if("json" in handler){
                res.writeHead(200, {'Content-Type': 'application/json'});
                res.returnObject = jsonify;
                handler.json(req,res);
                return;
            }

            if("html" in handler){

                res.writeHead(200, {'Content-Type': 'text/html'});
                if("args" in handler){//actual template
                    res.returnObject = htmlify(handler.compiled);
                    handler.args(req,res);
                }
                else
                    res.end(htmlify(handler.compiled)());
            }

            return;
        }

    }

    throw new Error(pathname +" >> No mapping for this path");
}
//--------------------------------------------------
Ys.run = function(port,host){

    if(!port)
        port = 8780;

    if(!host)
        host= "127.0.0.1";

    var mimes_raw  = fs.readFileSync('/etc/mime.types','utf-8').split('\n')
    for(var i=0; i<mimes_raw.length; i++){
        var next = mimes_raw[i].split(/\s+/g)
        if(next && next.length >= 2)
            for(var j=1; j < next.length; j++)
                mime_types[next[j]] = next[0];
    }

    //correction for some types
    //mime_types["mp3"] = "audio/mp3";
    process.on('uncaughtException', function (err) {
            var str = err.stack;
            console.log(str);
            //res.end(str);
    });

    http.createServer(function (req, res) {

        try{
            handle_request(req,res);
        }
        catch(e){
            var str = e.stack;
            console.log(str);
            res.end(str);
        }

    }).listen(port,host);
    console.log('Server running at '+host+':'+port+'/');
}
//--------------------------------------------------
<|endoftext|>


<commit_before>// Data types used in the OpenType font file.
// All OpenType fonts use Motorola-style byte ordering (Big Endian)

'use strict';

var check = require('./check');

var LIMIT16 = 32768; // The limit at which a 16-bit number switches signs == 2^15
var LIMIT32 = 2147483648; // The limit at which a 32-bit number switches signs == 2 ^ 31

var decode = {};
var encode = {};
var sizeOf = {};

// Return a function that always returns the same value.
function constant(v) {
    return function () {
        return v;
    };
}

// OpenType data types //////////////////////////////////////////////////////

// Convert an 8-bit unsigned integer to a list of 1 byte.
encode.BYTE = function (v) {
    check.argument(v >= 0 && v <= 255, 'Byte value should be between 0 and 255.');
    return [v];
};

sizeOf.BYTE = constant(1);

// Convert a 8-bit signed integer to a list of 1 byte.
encode.CHAR = function (v) {
    return [v.charCodeAt(0)];
};

sizeOf.BYTE = constant(1);

// Convert an ASCII string to a list of bytes.
encode.CHARARRAY = function (v) {
    var b = [];
    for (var i = 0; i < v.length; i += 1) {
        b.push(v.charCodeAt(i));
    }
    return b;
};

sizeOf.CHARARRAY = function (v) {
    return v.length;
};

// Convert a 16-bit unsigned integer to a list of 2 bytes.
encode.USHORT = function (v) {
    return [(v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.USHORT = constant(2);

// Convert a 16-bit signed integer to a list of 2 bytes.
encode.SHORT = function (v) {
    // Two's complement
    if (v >= LIMIT16){
        v = - ( 2 * LIMIT16 - v);
    }
    return [(v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.SHORT = constant(2);

// Convert a 24-bit unsigned integer to a list of 3 bytes.
encode.UINT24 = function (v) {
    return [(v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.UINT24 = constant(3);

// Convert a 32-bit unsigned integer to a list of 4 bytes.
encode.ULONG = function (v) {
    return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.ULONG = constant(4);

// Convert a 32-bit unsigned integer to a list of 4 bytes.
encode.LONG = function (v) {
     // Two's complement
    if (v >= LIMIT32){
        v = - ( 2 * LIMIT32 - v);
    }
    return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.LONG = constant(4);

encode.FIXED = encode.ULONG;
sizeOf.FIXED = sizeOf.ULONG;

encode.FWORD = encode.SHORT;
sizeOf.FWORD = sizeOf.SHORT;

encode.UFWORD = encode.USHORT;
sizeOf.UFWORD = sizeOf.USHORT;

// FIXME Implement LONGDATETIME
encode.LONGDATETIME = function () {
    return [0, 0, 0, 0, 0, 0, 0, 0];
};

sizeOf.LONGDATETIME = constant(8);

// Convert a 4-char tag to a list of 4 bytes.
encode.TAG = function (v) {
    check.argument(v.length === 4, 'Tag should be exactly 4 ASCII characters.');
    return [v.charCodeAt(0),
            v.charCodeAt(1),
            v.charCodeAt(2),
            v.charCodeAt(3)];
};

sizeOf.TAG = constant(4);

// CFF data types ///////////////////////////////////////////////////////////

encode.Card8 = encode.BYTE;
sizeOf.Card8 = sizeOf.BYTE;

encode.Card16 = encode.USHORT;
sizeOf.Card16 = sizeOf.USHORT;

encode.OffSize = encode.BYTE;
sizeOf.OffSize = sizeOf.BYTE;

encode.SID = encode.USHORT;
sizeOf.SID = sizeOf.USHORT;

// Convert a numeric operand or charstring number to a variable-size list of bytes.
encode.NUMBER = function (v) {
    var v2, b0, b1;
    if (v >= -107 && v <= 107) {
        return [v + 139];
    } else if (v >= 108 && v <= 1131 ) {
        v2 = v - 108;
        b0 = (v2 >> 8) & 0xFF;
        b1 = v2 - (b0 << 8);
        return [b0 + 247, b1];
    } else if (v >= -1131 && v <= -108) {
        v2 = -v - 108;
        b0 = (v2 >> 8) & 0xFF;
        b1 = v2 - (b0 << 8);
        return [b0 + 251, b1];
    } else if (v >= -32768 && v <= 32767) {
        return encode.NUMBER16(v);
    } else {
        return encode.NUMBER32(v);
    }
};

sizeOf.NUMBER = function (v) {
    return encode.NUMBER(v).length;
};

// Convert a signed number between -32768 and +32767 to a two-byte value.
// This ensures we always two bytes, but is not the most compact format.
encode.NUMBER16 = function (v) {
    return [28, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.NUMBER16 = constant(2);

// Convert a signed number between -(2^31) and +(2^31-1) to a four-byte value.
// This is useful if you want to be sure you always use four bytes,
// at the expense of wasting a few bytes for smaller numbers.
encode.NUMBER32 = function (v) {
    return [29, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.NUMBER32 = constant(4);

encode.NAME = encode.CHARARRAY;
sizeOf.NAME = sizeOf.CHARARRAY;

encode.STRING = encode.CHARARRAY;
sizeOf.STRING = sizeOf.CHARARRAY;

// Convert a ASCII string to a list of UTF16 bytes.
encode.UTF16 = function (v) {
    var b = [];
    for (var i = 0; i < v.length; i += 1) {
        b.push(0);
        b.push(v.charCodeAt(i));
    }
    return b;
};

sizeOf.UTF16 = function (v) {
    return v.length * 2;
};

// Convert a list of values to a CFF INDEX structure.
// The values should be objects containing name / type / value.
encode.INDEX = function (l) {
    var count, offSize, offset, offsets, offsetEncoder, encodedOffset, data, i, v;
    if (l.length === 0) {
        return [0, 0];
    }
    count = encode.Card16(l.length);
    offSize = (1 + Math.floor(Math.log(l.length)/Math.log(2)) / 8) | 0;
    offset = 1;
    offsets = [];
    offsetEncoder = [undefined, encode.BYTE, encode.USHORT, encode.UINT24, encode.ULONG][offSize];
    data = [];
    offsets.push(1); // First offset is always 1.
    for (i = 0; i < l.length; i += 1) {
        v = encode.OBJECT(l[i]);
        Array.prototype.push.apply(data, v);
        offset += v.length;
        encodedOffset = offsetEncoder(offset);
        Array.prototype.push.apply(offsets, encodedOffset);
    }
    return Array.prototype.concat(count,
                           encode.OffSize(offSize),
                           offsets,
                           data);
};

sizeOf.INDEX = function (v) {
    return encode.INDEX(v).length;
};

// Convert an object to a CFF DICT structure.
// The keys should be numeric.
// The values should be objects containing name / type / value.
encode.DICT = function (m) {
    var d = [];
    var keys = Object.keys(m);
    for (var i = 0; i < keys.length; i += 1) {
        // Object.keys() return string keys, but our keys are always numeric.
        var k = parseInt(keys[i], 0);
        var v = m[k];
        // Value comes before the key.
        d = d.concat(encode.OPERAND(v.value, v.type));
        d = d.concat(encode.OPERATOR(k));
    }
    return d;
};

sizeOf.DICT = function (m) {
    return encode.DICT(m).length;
};

encode.OPERATOR = function (v) {
    if (v < 1200) {
        return [v];
    } else {
        return [12, v - 1200];
    }
};

encode.OPERAND = function (v, type) {
    var d, i;
    d = [];
    if (Array.isArray(type)) {
        for (i = 0; i < type.length; i += 1) {
            check.argument(v.length === type.length, 'Not enough arguments given for type' + type);
            d = d.concat(encode.OPERAND(v[i], type[i]));
        }
    } else {
        if (type === 'SID') {
            d = d.concat(encode.NUMBER(v));
        } else if (type === 'offset') {
            // We make it easy for ourselves and always encode offsets as
            // 4 bytes. This makes offset calculation for the top dict easier.
            d = d.concat(encode.NUMBER32(v));
        } else {
            // FIXME Add support for booleans
            d = d.concat(encode.NUMBER(v));
        }
    }
    return d;
};

encode.OP = encode.BYTE;
sizeOf.OP = sizeOf.BYTE;

// Convert a list of CharString operations to bytes.
encode.CHARSTRING = function (ops) {
    var d = [], i;
    for (i = 0; i < ops.length; i += 1) {
        var op = ops[i];
        var encodingFunction = encode[op.type];
        d = d.concat(encodingFunction(op.value));
    }
    return d;
};

sizeOf.CHARSTRING = function (ops) {
    return encode.CHARSTRING(ops).length;
};

// Utility functions ////////////////////////////////////////////////////////

// Convert an object containing name / type / value to bytes.
encode.OBJECT = function (v) {
    var encodingFunction = encode[v.type];
    check.argument(encodingFunction !== undefined, 'No encoding function for type ' + v.type);
    return encodingFunction(v.value);
};

// Convert a table object to bytes.
// A table contains a list of fields containing the metadata (name, type and default value).
// The table itself has the field values set as attributes.
encode.TABLE = function (table) {
    var d = [];
    for (var i = 0; i < table.fields.length; i += 1) {
        var field = table.fields[i];
        var encodingFunction = encode[field.type];
        check.argument(encodingFunction !== undefined, 'No encoding function for field type ' + field.type);
        var value = table[field.name];
        if (value === undefined) {
            value = field.value;
        }
        var bytes = encodingFunction(value);
        d = d.concat(bytes);
    }
    return d;
};

// Merge in a list of bytes.
encode.LITERAL = function (v) {
    return v;
};

sizeOf.LITERAL = function (v) {
    return v.length;
};

exports.decode = decode;
exports.encode = encode;
exports.sizeOf = sizeOf;
<commit_msg>Correct encoding of larger INDEX data structures.<commit_after>// Data types used in the OpenType font file.
// All OpenType fonts use Motorola-style byte ordering (Big Endian)

'use strict';

var check = require('./check');

var LIMIT16 = 32768; // The limit at which a 16-bit number switches signs == 2^15
var LIMIT32 = 2147483648; // The limit at which a 32-bit number switches signs == 2 ^ 31

var decode = {};
var encode = {};
var sizeOf = {};

// Return a function that always returns the same value.
function constant(v) {
    return function () {
        return v;
    };
}

// OpenType data types //////////////////////////////////////////////////////

// Convert an 8-bit unsigned integer to a list of 1 byte.
encode.BYTE = function (v) {
    check.argument(v >= 0 && v <= 255, 'Byte value should be between 0 and 255.');
    return [v];
};

sizeOf.BYTE = constant(1);

// Convert a 8-bit signed integer to a list of 1 byte.
encode.CHAR = function (v) {
    return [v.charCodeAt(0)];
};

sizeOf.BYTE = constant(1);

// Convert an ASCII string to a list of bytes.
encode.CHARARRAY = function (v) {
    var b = [];
    for (var i = 0; i < v.length; i += 1) {
        b.push(v.charCodeAt(i));
    }
    return b;
};

sizeOf.CHARARRAY = function (v) {
    return v.length;
};

// Convert a 16-bit unsigned integer to a list of 2 bytes.
encode.USHORT = function (v) {
    return [(v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.USHORT = constant(2);

// Convert a 16-bit signed integer to a list of 2 bytes.
encode.SHORT = function (v) {
    // Two's complement
    if (v >= LIMIT16){
        v = - ( 2 * LIMIT16 - v);
    }
    return [(v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.SHORT = constant(2);

// Convert a 24-bit unsigned integer to a list of 3 bytes.
encode.UINT24 = function (v) {
    return [(v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.UINT24 = constant(3);

// Convert a 32-bit unsigned integer to a list of 4 bytes.
encode.ULONG = function (v) {
    return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.ULONG = constant(4);

// Convert a 32-bit unsigned integer to a list of 4 bytes.
encode.LONG = function (v) {
     // Two's complement
    if (v >= LIMIT32){
        v = - ( 2 * LIMIT32 - v);
    }
    return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.LONG = constant(4);

encode.FIXED = encode.ULONG;
sizeOf.FIXED = sizeOf.ULONG;

encode.FWORD = encode.SHORT;
sizeOf.FWORD = sizeOf.SHORT;

encode.UFWORD = encode.USHORT;
sizeOf.UFWORD = sizeOf.USHORT;

// FIXME Implement LONGDATETIME
encode.LONGDATETIME = function () {
    return [0, 0, 0, 0, 0, 0, 0, 0];
};

sizeOf.LONGDATETIME = constant(8);

// Convert a 4-char tag to a list of 4 bytes.
encode.TAG = function (v) {
    check.argument(v.length === 4, 'Tag should be exactly 4 ASCII characters.');
    return [v.charCodeAt(0),
            v.charCodeAt(1),
            v.charCodeAt(2),
            v.charCodeAt(3)];
};

sizeOf.TAG = constant(4);

// CFF data types ///////////////////////////////////////////////////////////

encode.Card8 = encode.BYTE;
sizeOf.Card8 = sizeOf.BYTE;

encode.Card16 = encode.USHORT;
sizeOf.Card16 = sizeOf.USHORT;

encode.OffSize = encode.BYTE;
sizeOf.OffSize = sizeOf.BYTE;

encode.SID = encode.USHORT;
sizeOf.SID = sizeOf.USHORT;

// Convert a numeric operand or charstring number to a variable-size list of bytes.
encode.NUMBER = function (v) {
    var v2, b0, b1;
    if (v >= -107 && v <= 107) {
        return [v + 139];
    } else if (v >= 108 && v <= 1131 ) {
        v2 = v - 108;
        b0 = (v2 >> 8) & 0xFF;
        b1 = v2 - (b0 << 8);
        return [b0 + 247, b1];
    } else if (v >= -1131 && v <= -108) {
        v2 = -v - 108;
        b0 = (v2 >> 8) & 0xFF;
        b1 = v2 - (b0 << 8);
        return [b0 + 251, b1];
    } else if (v >= -32768 && v <= 32767) {
        return encode.NUMBER16(v);
    } else {
        return encode.NUMBER32(v);
    }
};

sizeOf.NUMBER = function (v) {
    return encode.NUMBER(v).length;
};

// Convert a signed number between -32768 and +32767 to a two-byte value.
// This ensures we always two bytes, but is not the most compact format.
encode.NUMBER16 = function (v) {
    return [28, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.NUMBER16 = constant(2);

// Convert a signed number between -(2^31) and +(2^31-1) to a four-byte value.
// This is useful if you want to be sure you always use four bytes,
// at the expense of wasting a few bytes for smaller numbers.
encode.NUMBER32 = function (v) {
    return [29, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
};

sizeOf.NUMBER32 = constant(4);

encode.NAME = encode.CHARARRAY;
sizeOf.NAME = sizeOf.CHARARRAY;

encode.STRING = encode.CHARARRAY;
sizeOf.STRING = sizeOf.CHARARRAY;

// Convert a ASCII string to a list of UTF16 bytes.
encode.UTF16 = function (v) {
    var b = [];
    for (var i = 0; i < v.length; i += 1) {
        b.push(0);
        b.push(v.charCodeAt(i));
    }
    return b;
};

sizeOf.UTF16 = function (v) {
    return v.length * 2;
};

// Convert a list of values to a CFF INDEX structure.
// The values should be objects containing name / type / value.
encode.INDEX = function (l) {
    var offSize, offset, offsets, offsetEncoder, encodedOffsets, encodedOffset, data,
        dataSize, i, v;
    // Because we have to know which data type to use to encode the offsets,
    // we have to go through the values twice: once to encode the data and
    // calculate the offets, then again to encode the offsets using the fitting data type.
    offset = 1; // First offset is always 1.
    offsets = [offset];
    data = [];
    dataSize = 0;
    for (i = 0; i < l.length; i += 1) {
        v = encode.OBJECT(l[i]);
        Array.prototype.push.apply(data, v);
        dataSize += v.length;
        offset += v.length;
        offsets.push(offset);
    }

    if (data.length === 0) {
        return [0, 0];
    }

    encodedOffsets = [];
    offSize = (1 + Math.floor(Math.log(dataSize)/Math.log(2)) / 8) | 0;
    offsetEncoder = [undefined, encode.BYTE, encode.USHORT, encode.UINT24, encode.ULONG][offSize];
    for (i = 0; i < offsets.length; i += 1) {
        encodedOffset = offsetEncoder(offsets[i]);
        Array.prototype.push.apply(encodedOffsets, encodedOffset);
    }
    return Array.prototype.concat(encode.Card16(l.length),
                           encode.OffSize(offSize),
                           encodedOffsets,
                           data);
};

sizeOf.INDEX = function (v) {
    return encode.INDEX(v).length;
};

// Convert an object to a CFF DICT structure.
// The keys should be numeric.
// The values should be objects containing name / type / value.
encode.DICT = function (m) {
    var d = [];
    var keys = Object.keys(m);
    for (var i = 0; i < keys.length; i += 1) {
        // Object.keys() return string keys, but our keys are always numeric.
        var k = parseInt(keys[i], 0);
        var v = m[k];
        // Value comes before the key.
        d = d.concat(encode.OPERAND(v.value, v.type));
        d = d.concat(encode.OPERATOR(k));
    }
    return d;
};

sizeOf.DICT = function (m) {
    return encode.DICT(m).length;
};

encode.OPERATOR = function (v) {
    if (v < 1200) {
        return [v];
    } else {
        return [12, v - 1200];
    }
};

encode.OPERAND = function (v, type) {
    var d, i;
    d = [];
    if (Array.isArray(type)) {
        for (i = 0; i < type.length; i += 1) {
            check.argument(v.length === type.length, 'Not enough arguments given for type' + type);
            d = d.concat(encode.OPERAND(v[i], type[i]));
        }
    } else {
        if (type === 'SID') {
            d = d.concat(encode.NUMBER(v));
        } else if (type === 'offset') {
            // We make it easy for ourselves and always encode offsets as
            // 4 bytes. This makes offset calculation for the top dict easier.
            d = d.concat(encode.NUMBER32(v));
        } else {
            // FIXME Add support for booleans
            d = d.concat(encode.NUMBER(v));
        }
    }
    return d;
};

encode.OP = encode.BYTE;
sizeOf.OP = sizeOf.BYTE;

// Convert a list of CharString operations to bytes.
encode.CHARSTRING = function (ops) {
    var d = [], i;
    for (i = 0; i < ops.length; i += 1) {
        var op = ops[i];
        var encodingFunction = encode[op.type];
        d = d.concat(encodingFunction(op.value));
    }
    return d;
};

sizeOf.CHARSTRING = function (ops) {
    return encode.CHARSTRING(ops).length;
};

// Utility functions ////////////////////////////////////////////////////////

// Convert an object containing name / type / value to bytes.
encode.OBJECT = function (v) {
    var encodingFunction = encode[v.type];
    check.argument(encodingFunction !== undefined, 'No encoding function for type ' + v.type);
    return encodingFunction(v.value);
};

// Convert a table object to bytes.
// A table contains a list of fields containing the metadata (name, type and default value).
// The table itself has the field values set as attributes.
encode.TABLE = function (table) {
    var d = [];
    for (var i = 0; i < table.fields.length; i += 1) {
        var field = table.fields[i];
        var encodingFunction = encode[field.type];
        check.argument(encodingFunction !== undefined, 'No encoding function for field type ' + field.type);
        var value = table[field.name];
        if (value === undefined) {
            value = field.value;
        }
        var bytes = encodingFunction(value);
        d = d.concat(bytes);
    }
    return d;
};

// Merge in a list of bytes.
encode.LITERAL = function (v) {
    return v;
};

sizeOf.LITERAL = function (v) {
    return v.length;
};

exports.decode = decode;
exports.encode = encode;
exports.sizeOf = sizeOf;
<|endoftext|>


<commit_before>var utils = (function () {
    "use strict";
    var that = {},
        shorten,
        deep_replace,
        clone,
        MAX_CLONE_DEPTH = 10, // "constant"
        asc,
        desc,
        bisector_left;

    // shorten a sorted array to n elements, allowing more than n elements if
    // there are ties at the end
    // xs: array to shorten
    // n: desired length (result is shorter if xs is shorter, longer if there
    //    are ties at the end of xs
    // f: subscripting function: f(xs, i) = xs[i] by default
    shorten = function (xs, n, f) {
        var i, accessor = f;

        if (xs.length <= n) {
            return xs;
        }
        if (typeof f !== 'function') {
            accessor = function (a, i) { return a[i]; };
        }

        for (i = n; i < xs.length; i += 1) {
            if (accessor(xs, i) !== accessor(xs, n - 1)) {
                break;
            }
        }
        return xs.slice(0, i);
    };
    that.shorten = shorten;

    // replace the non-method properties of one object with those of
    // another without overwriting any properties in the original not
    // specified in the replacement OR adding any properties in the
    // replacement not specified in the original
    //
    // x: the original
    // repl: the source of replacements

    deep_replace = function (x, repl) {
        var prop, result = x;
        if (repl === undefined) {
            return x;
        }

        if (x === undefined) {
            return repl;
        }

        if (typeof repl === "object") {
            for (prop in repl) {
                if (repl.hasOwnProperty(prop)
                        && typeof repl[prop] !== 'function') {
                    result[prop] = deep_replace(x[prop], repl[prop]);
                }
            }
        } else if (typeof repl !== 'function') {
            result = repl;
        }
        return result;
    };
    that.deep_replace = deep_replace;

    // clone an object's data properties (strings, numbers, and booleans),
    // descending rescursively into arrays or objects. Anything else (e.g.
    // functions) is not cloned but simply returned. The maximum recursion
    // depth is MAX_CLONE_DEPTH to prevent infinite recursion if at some
    // depth an object holds a reference to itself.
    clone = function (x) {
        var cloner;
        cloner = function (x, depth) {
            var prop, result;

            if (typeof x === "string" || typeof x === "number"
                    || typeof x === "boolean") {
                return x;
            }

            if (depth > MAX_CLONE_DEPTH) {
                return undefined;
            }

            if (Array.isArray(x)) {
                return x.map(function (y) {
                    return cloner(y, depth + 1);
                });
            }

            if (typeof x === "object") {
                result = { };
                for (prop in x) {
                    if (x.hasOwnProperty(prop)) {
                        result[prop] = cloner(x[prop], depth + 1);
                    }
                }
                return result;
            }
            // otherwise
            return x;
        };
        return cloner(x, 0);
    };
    that.clone = clone;

    // These three functions are lifted straight from the d3 code so
    // that we can invoke them in a Worker that doesn't have a document
    // context, which d3 requires.
    //
    // For the code by Mike Bostock, see:
    // https://github.com/mbostock/d3/blob/master/src/arrays

    asc = function asc(a, b) {
        return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
    };
    that.asc = asc;

    desc = function(a, b) {
        return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
    };
    that.desc = desc;

    bisector_left = function (f) {
        var compare = (typeof f === "function") ?
            function(d, x) { return asc(f(d), x); }
            : asc;

        return function(a, x, lo, hi) {
            var mid;
            if (arguments.length < 3) {
                lo = 0;
            }
            if (arguments.length < 4) {
                hi = a.length;
            }
            while (lo < hi) {
                mid = lo + hi >>> 1;
                if (compare(a[mid], x) < 0) {
                    lo = mid + 1;
                } else {
                    hi = mid;
                }
            }
            return lo;
        };
    };
    that.bisector_left = bisector_left;

    that.bisect_left = that.bisector_left();

    return that;
}());
<commit_msg>x vs X in utils::clone<commit_after>var utils = (function () {
    "use strict";
    var that = {},
        shorten,
        deep_replace,
        clone,
        MAX_CLONE_DEPTH = 10, // "constant"
        asc,
        desc,
        bisector_left;

    // shorten a sorted array to n elements, allowing more than n elements if
    // there are ties at the end
    // xs: array to shorten
    // n: desired length (result is shorter if xs is shorter, longer if there
    //    are ties at the end of xs
    // f: subscripting function: f(xs, i) = xs[i] by default
    shorten = function (xs, n, f) {
        var i, accessor = f;

        if (xs.length <= n) {
            return xs;
        }
        if (typeof f !== 'function') {
            accessor = function (a, i) { return a[i]; };
        }

        for (i = n; i < xs.length; i += 1) {
            if (accessor(xs, i) !== accessor(xs, n - 1)) {
                break;
            }
        }
        return xs.slice(0, i);
    };
    that.shorten = shorten;

    // replace the non-method properties of one object with those of
    // another without overwriting any properties in the original not
    // specified in the replacement OR adding any properties in the
    // replacement not specified in the original
    //
    // x: the original
    // repl: the source of replacements

    deep_replace = function (x, repl) {
        var prop, result = x;
        if (repl === undefined) {
            return x;
        }

        if (x === undefined) {
            return repl;
        }

        if (typeof repl === "object") {
            for (prop in repl) {
                if (repl.hasOwnProperty(prop)
                        && typeof repl[prop] !== 'function') {
                    result[prop] = deep_replace(x[prop], repl[prop]);
                }
            }
        } else if (typeof repl !== 'function') {
            result = repl;
        }
        return result;
    };
    that.deep_replace = deep_replace;

    // clone an object's data properties (strings, numbers, and booleans),
    // descending rescursively into arrays or objects. Anything else (e.g.
    // functions) is not cloned but simply returned. The maximum recursion
    // depth is MAX_CLONE_DEPTH to prevent infinite recursion if at some
    // depth an object holds a reference to itself.
    clone = function (X) {
        var cloner;
        cloner = function (x, depth) {
            var prop, result;

            if (typeof x === "string" || typeof x === "number"
                    || typeof x === "boolean") {
                return x;
            }

            if (depth > MAX_CLONE_DEPTH) {
                return undefined;
            }

            if (Array.isArray(x)) {
                return x.map(function (y) {
                    return cloner(y, depth + 1);
                });
            }

            if (typeof x === "object") {
                result = { };
                for (prop in x) {
                    if (x.hasOwnProperty(prop)) {
                        result[prop] = cloner(x[prop], depth + 1);
                    }
                }
                return result;
            }
            // otherwise
            return x;
        };
        return cloner(X, 0);
    };
    that.clone = clone;

    // These three functions are lifted straight from the d3 code so
    // that we can invoke them in a Worker that doesn't have a document
    // context, which d3 requires.
    //
    // For the code by Mike Bostock, see:
    // https://github.com/mbostock/d3/blob/master/src/arrays

    asc = function asc(a, b) {
        return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
    };
    that.asc = asc;

    desc = function(a, b) {
        return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
    };
    that.desc = desc;

    bisector_left = function (f) {
        var compare = (typeof f === "function") ?
            function(d, x) { return asc(f(d), x); }
            : asc;

        return function(a, x, lo, hi) {
            var mid;
            if (arguments.length < 3) {
                lo = 0;
            }
            if (arguments.length < 4) {
                hi = a.length;
            }
            while (lo < hi) {
                mid = lo + hi >>> 1;
                if (compare(a[mid], x) < 0) {
                    lo = mid + 1;
                } else {
                    hi = mid;
                }
            }
            return lo;
        };
    };
    that.bisector_left = bisector_left;

    that.bisect_left = that.bisector_left();

    return that;
}());
<|endoftext|>