<commit_before>JS.ENV.UdonSpec = JS.Test.describe('Udon', function() { with (this) {
    before(function() {
        this.Udon     = JS.ENV.Udon;
        this.add      = function(a, b) { return a + b; };
        this.multiply = function(a, b) { return a * b; };
        this.cons     = function(car, cdr) { return [car].concat(cdr); };
        this.rcons    = function(car, cdr) { return [cdr].concat(car); };
        this.pair     = function(x, y) { return [x, y]; };
        this.id       = function(x) { return x === x; };
        this.nid      = function(x) { return x !== x; };
        this.sum      = function(ns) {
            var n = 0, m = ns.length;
            while (m--) n += ns[m];
            return n;
        };
        this.product  = function(ns) {
            var n = 1, m = ns.length;
            while (m--) n *= ns[m];
            return n;
        };
        this.reverse  = function(ns) {
            return ns.concat([]).reverse();
        };
    });

    describe('curry', function() {
        it('makes new functions each time it is called', function() { with(this) {
            var plus10, minus5;

            plus10 = Udon.curry(add)(10);

            assertEqual(15, plus10(5));
            assertEqual(-5, plus10(-15));

            minus5 = Udon.curry(add)(-5);

            assertEqual(15, minus5(20));
            assertEqual(-5, minus5(0));
        }});
    });

    describe('ncurry', function() {
        it('makes new functions of arity n', function() { with(this) {
            var add3   = function(a, b, c) { return a + b + c; },
                curry3 = Udon.ncurry(3),
                add3c  = curry3(add3);

            assertEqual(6, add3c(1, 2, 3));
            assertEqual(6, add3c(1, 2)(3));
            assertEqual(6, add3c(1)(2)(3));
        }});

        it('should not keep any state', function() { with(this) {
            var max3c = Udon.ncurry(3)(Math.max),
                max5  = max3c(5);

            assertEqual(10, max5(1)(10));
            assertEqual(5, max5(1, 2));
        }});
    });

    describe('compose', function() {
        it('should produce the same result as directly applying the composed functions', function() { with(this) {
            var tcs = Udon.compose([Math.sin, Math.cos, Math.tan]);

            assertEqual(Math.sin(Math.cos(Math.tan(0.7))), tcs(0.7));
        }});

        it('should accept an option arity argument making the composed function partially applicable', function() { with(this) {
            var ceilMax  = Udon.compose([Math.ceil, Math.max], 2),
                floorMin = Udon.compose([Math.floor, Math.min], 3);

            assertEqual(2, ceilMax(0.7)(1.1));
            assertEqual(1, ceilMax(0.7)(0.4));
            assertEqual(3, ceilMax(1.5)(2.4));

            assertEqual(4, floorMin(4.5, 5.2, 7.4));
            assertEqual(6, floorMin(6.1, 9.8, 6.2));
            assertEqual(1, floorMin(1.3, 6.2, 4.9));
        }});
    });

    describe('foldl', function() {
        it('can be used to implement sum', function() { with(this) {
            var ys = [9, 7, 4, 18, 27, 91, 412];

            assertEqual(sum(ys), Udon.foldl(add, 0, ys));
            assertEqual(0, Udon.foldl(add, 0, []));
        }});

        it('can be used to implement product', function() { with(this) {
            var ys = [24, 17, 61, 12];

            assertEqual(product(ys), Udon.foldl(multiply, 1, ys));
            assertEqual(1, Udon.foldl(multiply, 1, []));
        }});

        it('is equivalent to reverse on arrays when passed rcons and []', function() { with(this) {
            var ys = ['foo', 'bar', 'baz'];

            assertEqual(reverse(ys), Udon.foldl(rcons, [], ys));
            assertEqual([], Udon.foldl(rcons, [], []));
        }});
    });

    describe('foldr', function() {
        it('is the identity on arrays when passed cons and []', function() { with (this) {
            var xs = [1, 2, 3, 4];

            assertEqual(xs, Udon.foldr(cons, [], xs));
        }});

        it('preserves list structure', function() { with(this) {
            var ys = [5, 10, 15, 20],
                ps = [5, [10, [15, [20, []]]]];

            assertEqual(ps, Udon.foldr(pair, [], ys));
        }});

        it('can be used to implement map', function() { with(this) {
            var ys    = [0.7, 5.3, 7.1, 3.9],
                fCons = function(f) {
                    return function(car, cdr) {
                        return [f(car)].concat(cdr);
                    };
                };

            assertEqual(Udon.map(Math.floor, ys),
                Udon.foldr(fCons(Math.floor), [], ys));
        }});

        it('can turn arrays into lists', function() { with(this) {
            var list = {car: 1, cdr: {car: 2, cdr: {car: null, cdr: null}}},
                cell = function(head, tail) { return {car: head, cdr: tail}; };

            assertEqual(list, Udon.foldr(cell, {car: null, cdr: null}, [1, 2]));
        }});

        it('can be used to implement maximum', function() { with(this) {
            var ys = [1, 2, 4, 9, 3, 7];

            assertEqual(9, Udon.foldr(Math.max, -Infinity, ys));
        }});

        it('can be used to implement minimum', function() { with(this) {
            var ys = [1, 2, 4, 9, 3, 7];

            assertEqual(1, Udon.foldr(Math.min, Infinity, ys));
        }});
    });

    describe('map', function() {
        it('should return an array of the same length as that given', function() { with(this) {
            var zs = [null, null, null, null];

            assertEqual(zs.length, Udon.map(id, zs).length);
        }});

        it('should return an empty array when given one', function() { with(this) {
            assertEqual([], Udon.map(id, []));
        }});

        it('should apply a function to each element of an array', function() { with(this) {
            assertEqual([1, 2, 3, 4], Udon.map(Math.floor, [1.7, 2.4, 3.9, 4.1]));
        }});
    });

    describe('filter', function() {
        it('is the identity on arrays when passed the identity function', function() { with (this) {
            var zs = [5, 4, 3, 2, 1];

            assertEqual(zs, Udon.filter(id, zs));
        }});

        it('returns the empty list when passed the negation of the identity function', function() { with (this) {
            var xs = [8, 4, 2, 0];

            assertEqual([], Udon.filter(nid, xs));
        }});

        it('only returns those elements to which a predicate applies', function() { with(this) {
            var zs         = [-1, 22, -17, 15],
                isNegative = function(n) { return n < 0; };

            assertEqual([-1, -17], Udon.filter(isNegative, zs));
        }});
    });

    describe('any', function() {
        it('should return true if one element of an array satisfies a predicate', function() { with(this) {
            var over5 = function(n) {
                return n > 5;
            };

            assert(Udon.any(over5, [7, 1, 2, -5, 0]));
        }});

        it('should return false if no elements of an array satisfy a predicate', function() { with(this) {
            var isOdd = function(n) {
                return n % 2 == 1;
            };

            assert(!Udon.any(isOdd, [0, 2, 4, 6, 8, 10, 12]));
        }});

        it('should return false if the supplied array is empty', function() { with(this) {
            assert(!Udon.any(id, []));
        }});
    });

    describe('zip', function() {
        it('should create a list of pairs from a pair of lists', function() { with (this) {
            var z1 = Udon.zip([1, 2, 3], [1, 2, 3]),
                z2 = Udon.zip([1, 2], [1, 2, 3]),
                z3 = Udon.zip([1, 2, 3], [2, 3]);

            assertEqual([[1, 1], [2, 2], [3, 3]], z1);
            assertEqual([[1, 1], [2, 2]], z2);
            assertEqual([[1, 2], [2, 3]], z3);
        }});

        it('should return a list the same length as its shortest argument', function() { with (this) {
            var z1 = Udon.zip([], [1, 2, 3]),
                z2 = Udon.zip([1, 2, 3], []),
                z3 = Udon.zip([1, 2], [3, 4]),
                z4 = Udon.zip([1], [2, 3]);

            assertEqual(0, z1.length);
            assertEqual(0, z2.length);
            assertEqual(2, z3.length);
            assertEqual(1, z4.length);
        }});
    });

    describe('zipWith', function() {
        it('should do pairwise addition of two lists', function() { with (this) {
            assertEqual([2, 6, 12],
                Udon.zipWith(add, [1, 2, 3], [1, 4, 9]));
        }});

        it('should produce the same output as `zip` when given a pairing function', function() { with (this) {
            var pair = function(a, b) { return [a, b]; };

            assertEqual(Udon.zip(['a', 'b', 'c'], [5, 10, 20]),
                Udon.zipWith(pair, ['a', 'b', 'c'], [5, 10, 20]));
        }});
    });
}});
<commit_msg>Test cases for all.<commit_after>JS.ENV.UdonSpec = JS.Test.describe('Udon', function() { with (this) {
    before(function() {
        this.Udon     = JS.ENV.Udon;
        this.add      = function(a, b) { return a + b; };
        this.multiply = function(a, b) { return a * b; };
        this.cons     = function(car, cdr) { return [car].concat(cdr); };
        this.rcons    = function(car, cdr) { return [cdr].concat(car); };
        this.pair     = function(x, y) { return [x, y]; };
        this.id       = function(x) { return x === x; };
        this.nid      = function(x) { return x !== x; };
        this.sum      = function(ns) {
            var n = 0, m = ns.length;
            while (m--) n += ns[m];
            return n;
        };
        this.product  = function(ns) {
            var n = 1, m = ns.length;
            while (m--) n *= ns[m];
            return n;
        };
        this.reverse  = function(ns) {
            return ns.concat([]).reverse();
        };
    });

    describe('curry', function() {
        it('makes new functions each time it is called', function() { with(this) {
            var plus10, minus5;

            plus10 = Udon.curry(add)(10);

            assertEqual(15, plus10(5));
            assertEqual(-5, plus10(-15));

            minus5 = Udon.curry(add)(-5);

            assertEqual(15, minus5(20));
            assertEqual(-5, minus5(0));
        }});
    });

    describe('ncurry', function() {
        it('makes new functions of arity n', function() { with(this) {
            var add3   = function(a, b, c) { return a + b + c; },
                curry3 = Udon.ncurry(3),
                add3c  = curry3(add3);

            assertEqual(6, add3c(1, 2, 3));
            assertEqual(6, add3c(1, 2)(3));
            assertEqual(6, add3c(1)(2)(3));
        }});

        it('should not keep any state', function() { with(this) {
            var max3c = Udon.ncurry(3)(Math.max),
                max5  = max3c(5);

            assertEqual(10, max5(1)(10));
            assertEqual(5, max5(1, 2));
        }});
    });

    describe('compose', function() {
        it('should produce the same result as directly applying the composed functions', function() { with(this) {
            var tcs = Udon.compose([Math.sin, Math.cos, Math.tan]);

            assertEqual(Math.sin(Math.cos(Math.tan(0.7))), tcs(0.7));
        }});

        it('should accept an option arity argument making the composed function partially applicable', function() { with(this) {
            var ceilMax  = Udon.compose([Math.ceil, Math.max], 2),
                floorMin = Udon.compose([Math.floor, Math.min], 3);

            assertEqual(2, ceilMax(0.7)(1.1));
            assertEqual(1, ceilMax(0.7)(0.4));
            assertEqual(3, ceilMax(1.5)(2.4));

            assertEqual(4, floorMin(4.5, 5.2, 7.4));
            assertEqual(6, floorMin(6.1, 9.8, 6.2));
            assertEqual(1, floorMin(1.3, 6.2, 4.9));
        }});
    });

    describe('foldl', function() {
        it('can be used to implement sum', function() { with(this) {
            var ys = [9, 7, 4, 18, 27, 91, 412];

            assertEqual(sum(ys), Udon.foldl(add, 0, ys));
            assertEqual(0, Udon.foldl(add, 0, []));
        }});

        it('can be used to implement product', function() { with(this) {
            var ys = [24, 17, 61, 12];

            assertEqual(product(ys), Udon.foldl(multiply, 1, ys));
            assertEqual(1, Udon.foldl(multiply, 1, []));
        }});

        it('is equivalent to reverse on arrays when passed rcons and []', function() { with(this) {
            var ys = ['foo', 'bar', 'baz'];

            assertEqual(reverse(ys), Udon.foldl(rcons, [], ys));
            assertEqual([], Udon.foldl(rcons, [], []));
        }});
    });

    describe('foldr', function() {
        it('is the identity on arrays when passed cons and []', function() { with (this) {
            var xs = [1, 2, 3, 4];

            assertEqual(xs, Udon.foldr(cons, [], xs));
        }});

        it('preserves list structure', function() { with(this) {
            var ys = [5, 10, 15, 20],
                ps = [5, [10, [15, [20, []]]]];

            assertEqual(ps, Udon.foldr(pair, [], ys));
        }});

        it('can be used to implement map', function() { with(this) {
            var ys    = [0.7, 5.3, 7.1, 3.9],
                fCons = function(f) {
                    return function(car, cdr) {
                        return [f(car)].concat(cdr);
                    };
                };

            assertEqual(Udon.map(Math.floor, ys),
                Udon.foldr(fCons(Math.floor), [], ys));
        }});

        it('can turn arrays into lists', function() { with(this) {
            var list = {car: 1, cdr: {car: 2, cdr: {car: null, cdr: null}}},
                cell = function(head, tail) { return {car: head, cdr: tail}; };

            assertEqual(list, Udon.foldr(cell, {car: null, cdr: null}, [1, 2]));
        }});

        it('can be used to implement maximum', function() { with(this) {
            var ys = [1, 2, 4, 9, 3, 7];

            assertEqual(9, Udon.foldr(Math.max, -Infinity, ys));
        }});

        it('can be used to implement minimum', function() { with(this) {
            var ys = [1, 2, 4, 9, 3, 7];

            assertEqual(1, Udon.foldr(Math.min, Infinity, ys));
        }});
    });

    describe('map', function() {
        it('should return an array of the same length as that given', function() { with(this) {
            var zs = [null, null, null, null];

            assertEqual(zs.length, Udon.map(id, zs).length);
        }});

        it('should return an empty array when given one', function() { with(this) {
            assertEqual([], Udon.map(id, []));
        }});

        it('should apply a function to each element of an array', function() { with(this) {
            assertEqual([1, 2, 3, 4], Udon.map(Math.floor, [1.7, 2.4, 3.9, 4.1]));
        }});
    });

    describe('filter', function() {
        it('is the identity on arrays when passed the identity function', function() { with (this) {
            var zs = [5, 4, 3, 2, 1];

            assertEqual(zs, Udon.filter(id, zs));
        }});

        it('returns the empty list when passed the negation of the identity function', function() { with (this) {
            var xs = [8, 4, 2, 0];

            assertEqual([], Udon.filter(nid, xs));
        }});

        it('only returns those elements to which a predicate applies', function() { with(this) {
            var zs         = [-1, 22, -17, 15],
                isNegative = function(n) { return n < 0; };

            assertEqual([-1, -17], Udon.filter(isNegative, zs));
        }});
    });

    describe('any', function() {
        it('should return true if one element of an array satisfies a predicate', function() { with(this) {
            var over5 = function(n) { return n > 5; };

            assert(Udon.any(over5, [7, 1, 2, -5, 0]));
        }});

        it('should return false if no elements of an array satisfy a predicate', function() { with(this) {
            var isOdd = function(n) { return n % 2 == 1; };

            assert(!Udon.any(isOdd, [0, 2, 4, 6, 8, 10, 12]));
        }});

        it('should return false if the supplied array is empty', function() { with(this) {
            assert(!Udon.any(id, []));
        }});
    });

    describe('all', function() {
        it('should return true if every element of an array satisfies a predicate', function() { with(this) {
            var isEven = function(n) { return n % 2 == 0; };

            assert(Udon.all(isEven, [2, 4, 8, 16]));
        }});

        it('should return false if any element of an array fails to satisfy a predicate', function() { with(this) {
            var isPositive = function(n) { return n > 0; };

            assert(!Udon.all(isPositive, [17, 9, 4, -2, 1, 0]));
        }});

        it('should return true if the supplied array is empty', function() { with(this) {
            assert(Udon.all(id, []));
        }});
    });

    describe('zip', function() {
        it('should create a list of pairs from a pair of lists', function() { with (this) {
            var z1 = Udon.zip([1, 2, 3], [1, 2, 3]),
                z2 = Udon.zip([1, 2], [1, 2, 3]),
                z3 = Udon.zip([1, 2, 3], [2, 3]);

            assertEqual([[1, 1], [2, 2], [3, 3]], z1);
            assertEqual([[1, 1], [2, 2]], z2);
            assertEqual([[1, 2], [2, 3]], z3);
        }});

        it('should return a list the same length as its shortest argument', function() { with (this) {
            var z1 = Udon.zip([], [1, 2, 3]),
                z2 = Udon.zip([1, 2, 3], []),
                z3 = Udon.zip([1, 2], [3, 4]),
                z4 = Udon.zip([1], [2, 3]);

            assertEqual(0, z1.length);
            assertEqual(0, z2.length);
            assertEqual(2, z3.length);
            assertEqual(1, z4.length);
        }});
    });

    describe('zipWith', function() {
        it('should do pairwise addition of two lists', function() { with (this) {
            assertEqual([2, 6, 12],
                Udon.zipWith(add, [1, 2, 3], [1, 4, 9]));
        }});

        it('should produce the same output as `zip` when given a pairing function', function() { with (this) {
            var pair = function(a, b) { return [a, b]; };

            assertEqual(Udon.zip(['a', 'b', 'c'], [5, 10, 20]),
                Udon.zipWith(pair, ['a', 'b', 'c'], [5, 10, 20]));
        }});
    });
}});
<|endoftext|>


<commit_before>
/*!
 * Stylus - utils
 * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var nodes = require('./nodes')
  , join = require('path').join
  , resolve = require('path').resolve
  , fs = require('fs');

/**
 * Check if `path` looks absolute.
 *
 * @param {String} path
 * @return {Boolean}
 * @api private
 */

exports.absolute = function(path){
  // On Windows the path could start with a drive letter, i.e. a:\\ or two leading backslashes
  return path.substr(0, 2) == '\\\\' || path[0] == '/' || /^[a-z]:\\/i.test(path);
};

/**
 * Attempt to lookup `path` within `paths` from tail to head.
 * Optionally a path to `ignore` may be passed.
 *
 * @param {String} path
 * @param {String} paths
 * @param {String} ignore
 * @param {Boolean} resolveURL
 * @return {String}
 * @api private
 */

exports.lookup = function(path, paths, ignore, resolveURL){
  var lookup
    , i = paths.length;

  // Absolute
  if (exports.absolute(path)) {
    try {
      fs.statSync(path);
      return path;
    } catch (err) {
      // Ignore, continue on
      // to trying relative lookup.
      // Needed for url(/images/foo.png)
      // for example
    }
  }

  // Relative
  while (i--) {
    try {
      lookup = (resolveURL ? resolve : join)(paths[i], path);
      if (ignore == lookup) continue;
      fs.statSync(lookup);
      return lookup;
    } catch (err) {
      // Ignore
    }
  }
};

/**
 * Format the given `err` with the given `options`.
 *
 * Options:
 *
 *   - `filename`   context filename
 *   - `context`    context line count [8]
 *   - `lineno`     context line number
 *   - `input`        input string
 *
 * @param {Error} err
 * @param {Object} options
 * @return {Error}
 * @api private
 */

exports.formatException = function(err, options){
  var lineno = options.lineno
    , filename = options.filename
    , str = options.input
    , context = options.context || 8
    , context = context / 2
    , lines = ('\n' + str).split('\n')
    , start = Math.max(lineno - context, 1)
    , end = Math.min(lines.length, lineno + context)
    , pad = end.toString().length;

  var context = lines.slice(start, end).map(function(line, i){
    var curr = i + start;
    return (curr == lineno ? ' > ' : '   ')
      + Array(pad - curr.toString().length + 1).join(' ')
      + curr
      + '| '
      + line;
  }).join('\n');

  err.message = filename
    + ':' + lineno
    + '\n' + context
    + '\n\n' + err.message + '\n'
    + (err.stylusStack ? err.stylusStack + '\n' : '');

  return err;
};

/**
 * Assert that `node` is of the given `type`, or throw.
 *
 * @param {Node} node
 * @param {Function} type
 * @param {String} param
 * @api public
 */

exports.assertType = function(node, type, param){
  exports.assertPresent(node, param);
  if (node.nodeName == type) return;
  var actual = node.nodeName
    , msg = 'expected "'
      + param + '" to be a '
      + type + ', but got '
      + actual + ':' + node;
  throw new Error('TypeError: ' + msg);
};

/**
 * Assert that `node` is a `String` or `Ident`.
 *
 * @param {Node} node
 * @param {String} param
 * @api public
 */

exports.assertString = function(node, param){
  exports.assertPresent(node, param);
  switch (node.nodeName) {
    case 'string':
    case 'ident':
    case 'literal':
      return;
    default:
      var actual = node.nodeName
        , msg = 'expected string, ident or literal, but got ' + actual + ':' + node;
      throw new Error('TypeError: ' + msg);
  }
};

/**
 * Assert that `node` is a `RGBA` or `HSLA`.
 *
 * @param {Node} node
 * @param {String} param
 * @api public
 */

exports.assertColor = function(node, param){
  exports.assertPresent(node, param);
  switch (node.nodeName) {
    case 'rgba':
    case 'hsla':
      return;
    default:
      var actual = node.nodeName
        , msg = 'expected rgba or hsla, but got ' + actual + ':' + node;
      throw new Error('TypeError: ' + msg);
  }
};

/**
 * Assert that param `name` is given, aka the `node` is passed.
 *
 * @param {Node} node
 * @param {String} name
 * @api public
 */

exports.assertPresent = function(node, name){
  if (node) return;
  if (name) throw new Error('"' + name + '" argument required');
  throw new Error('argument missing');
};

/**
 * Unwrap `expr`.
 *
 * Takes an expressions with length of 1
 * such as `((1 2 3))` and unwraps it to `(1 2 3)`.
 *
 * @param {Expression} expr
 * @return {Node}
 * @api public
 */

exports.unwrap = function(expr){
  // explicitly preserve the expression
  if (expr.preserve) return expr;
  if ('arguments' != expr.nodeName && 'expression' != expr.nodeName) return expr;
  if (1 != expr.nodes.length) return expr;
  if ('arguments' != expr.nodes[0].nodeName && 'expression' != expr.nodes[0].nodeName) return expr;
  return exports.unwrap(expr.nodes[0]);
};

/**
 * Coerce JavaScript values to their Stylus equivalents.
 *
 * @param {Mixed} val
 * @return {Node}
 * @api public
 */

exports.coerce = function(val){
  switch (typeof val) {
    case 'function':
      return val;
    case 'string':
      return new nodes.String(val);
    case 'boolean':
      return new nodes.Boolean(val);
    case 'number':
      return new nodes.Unit(val);
    default:
      if (null == val) return nodes.null;
      if (Array.isArray(val)) return exports.coerceArray(val);
      if (val.nodeName) return val;
      return exports.coerceObject(val);
  }
};

/**
 * Coerce a javascript `Array` to a Stylus `Expression`.
 *
 * @param {Array} val
 * @return {Expression}
 * @api private
 */

exports.coerceArray = function(val){
  var expr = new nodes.Expression;
  val.forEach(function(val){
    expr.push(exports.coerce(val));
  });
  return expr;
};

/**
 * Coerce a javascript object to a Stylus `Expression`.
 *
 * For example `{ foo: 'bar', bar: 'baz' }` would become
 * the expression `(foo 'bar') (bar 'baz')`.
 *
 * @param {Object} obj
 * @return {Expression}
 * @api public
 */

exports.coerceObject = function(obj){
  var expr = new nodes.Expression
    , val;

  for (var key in obj) {
    val = exports.coerce(obj[key]);
    key = new nodes.Ident(key);
    expr.push(exports.coerceArray([key, val]));
  }

  return expr;
};

/**
 * Return param names for `fn`.
 *
 * @param {Function} fn
 * @return {Array}
 * @api private
 */

exports.params = function(fn){
  return fn
    .toString()
    .match(/\(([^)]*)\)/)[1].split(/ *, */);
};

/**
 * Merge object `b` with `a`.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object} a
 * @api private
 */

exports.merge = function(a, b){
  for (var k in b) a[k] = b[k];
  return a;
}
<commit_msg>small optimization<commit_after>
/*!
 * Stylus - utils
 * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var nodes = require('./nodes')
  , join = require('path').join
  , resolve = require('path').resolve
  , fs = require('fs');

/**
 * Check if `path` looks absolute.
 *
 * @param {String} path
 * @return {Boolean}
 * @api private
 */

exports.absolute = function(path){
  // On Windows the path could start with a drive letter, i.e. a:\\ or two leading backslashes
  return path.substr(0, 2) == '\\\\' || path[0] == '/' || /^[a-z]:\\/i.test(path);
};

/**
 * Attempt to lookup `path` within `paths` from tail to head.
 * Optionally a path to `ignore` may be passed.
 *
 * @param {String} path
 * @param {String} paths
 * @param {String} ignore
 * @param {Boolean} resolveURL
 * @return {String}
 * @api private
 */

exports.lookup = function(path, paths, ignore, resolveURL){
  var lookup
    , method = resolveURL ? resolve : join
    , i = paths.length;

  // Absolute
  if (exports.absolute(path)) {
    try {
      fs.statSync(path);
      return path;
    } catch (err) {
      // Ignore, continue on
      // to trying relative lookup.
      // Needed for url(/images/foo.png)
      // for example
    }
  }

  // Relative
  while (i--) {
    try {
      lookup = method(paths[i], path);
      if (ignore == lookup) continue;
      fs.statSync(lookup);
      return lookup;
    } catch (err) {
      // Ignore
    }
  }
};

/**
 * Format the given `err` with the given `options`.
 *
 * Options:
 *
 *   - `filename`   context filename
 *   - `context`    context line count [8]
 *   - `lineno`     context line number
 *   - `input`        input string
 *
 * @param {Error} err
 * @param {Object} options
 * @return {Error}
 * @api private
 */

exports.formatException = function(err, options){
  var lineno = options.lineno
    , filename = options.filename
    , str = options.input
    , context = options.context || 8
    , context = context / 2
    , lines = ('\n' + str).split('\n')
    , start = Math.max(lineno - context, 1)
    , end = Math.min(lines.length, lineno + context)
    , pad = end.toString().length;

  var context = lines.slice(start, end).map(function(line, i){
    var curr = i + start;
    return (curr == lineno ? ' > ' : '   ')
      + Array(pad - curr.toString().length + 1).join(' ')
      + curr
      + '| '
      + line;
  }).join('\n');

  err.message = filename
    + ':' + lineno
    + '\n' + context
    + '\n\n' + err.message + '\n'
    + (err.stylusStack ? err.stylusStack + '\n' : '');

  return err;
};

/**
 * Assert that `node` is of the given `type`, or throw.
 *
 * @param {Node} node
 * @param {Function} type
 * @param {String} param
 * @api public
 */

exports.assertType = function(node, type, param){
  exports.assertPresent(node, param);
  if (node.nodeName == type) return;
  var actual = node.nodeName
    , msg = 'expected "'
      + param + '" to be a '
      + type + ', but got '
      + actual + ':' + node;
  throw new Error('TypeError: ' + msg);
};

/**
 * Assert that `node` is a `String` or `Ident`.
 *
 * @param {Node} node
 * @param {String} param
 * @api public
 */

exports.assertString = function(node, param){
  exports.assertPresent(node, param);
  switch (node.nodeName) {
    case 'string':
    case 'ident':
    case 'literal':
      return;
    default:
      var actual = node.nodeName
        , msg = 'expected string, ident or literal, but got ' + actual + ':' + node;
      throw new Error('TypeError: ' + msg);
  }
};

/**
 * Assert that `node` is a `RGBA` or `HSLA`.
 *
 * @param {Node} node
 * @param {String} param
 * @api public
 */

exports.assertColor = function(node, param){
  exports.assertPresent(node, param);
  switch (node.nodeName) {
    case 'rgba':
    case 'hsla':
      return;
    default:
      var actual = node.nodeName
        , msg = 'expected rgba or hsla, but got ' + actual + ':' + node;
      throw new Error('TypeError: ' + msg);
  }
};

/**
 * Assert that param `name` is given, aka the `node` is passed.
 *
 * @param {Node} node
 * @param {String} name
 * @api public
 */

exports.assertPresent = function(node, name){
  if (node) return;
  if (name) throw new Error('"' + name + '" argument required');
  throw new Error('argument missing');
};

/**
 * Unwrap `expr`.
 *
 * Takes an expressions with length of 1
 * such as `((1 2 3))` and unwraps it to `(1 2 3)`.
 *
 * @param {Expression} expr
 * @return {Node}
 * @api public
 */

exports.unwrap = function(expr){
  // explicitly preserve the expression
  if (expr.preserve) return expr;
  if ('arguments' != expr.nodeName && 'expression' != expr.nodeName) return expr;
  if (1 != expr.nodes.length) return expr;
  if ('arguments' != expr.nodes[0].nodeName && 'expression' != expr.nodes[0].nodeName) return expr;
  return exports.unwrap(expr.nodes[0]);
};

/**
 * Coerce JavaScript values to their Stylus equivalents.
 *
 * @param {Mixed} val
 * @return {Node}
 * @api public
 */

exports.coerce = function(val){
  switch (typeof val) {
    case 'function':
      return val;
    case 'string':
      return new nodes.String(val);
    case 'boolean':
      return new nodes.Boolean(val);
    case 'number':
      return new nodes.Unit(val);
    default:
      if (null == val) return nodes.null;
      if (Array.isArray(val)) return exports.coerceArray(val);
      if (val.nodeName) return val;
      return exports.coerceObject(val);
  }
};

/**
 * Coerce a javascript `Array` to a Stylus `Expression`.
 *
 * @param {Array} val
 * @return {Expression}
 * @api private
 */

exports.coerceArray = function(val){
  var expr = new nodes.Expression;
  val.forEach(function(val){
    expr.push(exports.coerce(val));
  });
  return expr;
};

/**
 * Coerce a javascript object to a Stylus `Expression`.
 *
 * For example `{ foo: 'bar', bar: 'baz' }` would become
 * the expression `(foo 'bar') (bar 'baz')`.
 *
 * @param {Object} obj
 * @return {Expression}
 * @api public
 */

exports.coerceObject = function(obj){
  var expr = new nodes.Expression
    , val;

  for (var key in obj) {
    val = exports.coerce(obj[key]);
    key = new nodes.Ident(key);
    expr.push(exports.coerceArray([key, val]));
  }

  return expr;
};

/**
 * Return param names for `fn`.
 *
 * @param {Function} fn
 * @return {Array}
 * @api private
 */

exports.params = function(fn){
  return fn
    .toString()
    .match(/\(([^)]*)\)/)[1].split(/ *, */);
};

/**
 * Merge object `b` with `a`.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object} a
 * @api private
 */

exports.merge = function(a, b){
  for (var k in b) a[k] = b[k];
  return a;
}
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');

var TOL = 1e-8;

/** @constructor */
var AssertException = function (message) {
    this.message = message || '(unspecified)';
};

AssertException.prototype.toString = function () {
    return 'Assertion Failed: ' + this.message;
};

var assert = function (condition, message) {
    if (!condition) {
        throw new AssertException(message);
    }
};

assert.Exception = AssertException;

assert.equal = function (actual, expected, message) {
    assert(_.isEqual(actual, expected),
        (message || '') +
        '\n  actual = ' + JSON.stringify(actual) +
        '\n  expected = ' + JSON.stringify(expected));
};

assert.close = function (x, y, message, tol) {
    message = message || 'Not close:';
    tol = tol || TOL;
    assert.equal(typeof x, typeof y);
    if (_.isNumber(x)) {
        assert(Math.abs(x - y) < tol,
            message +
            '\n  actual = ' + JSON.stringify(x) +
            '\n  expected = ' + JSON.stringify(y));
    } else if (_.isArray(x)) {
        assert.equal(x.length, y.length, message + ' lengths differ', tol);
        _.each(x, function (actual, pos) {
            var expected = y[pos];
            assert.close(actual, expected, message + ' [' + pos + ']', tol);
        });
    } else if (_.isObject(x)) {
        assert.equal(_.keys(x).sort(), _.keys(y).sort(), ' keys differ', tol);
        _.each(x, function (actual, key) {
            var expected = y[key];
            assert.close(actual, expected, message + ' [' + key + ']');
        });
    } else {
        assert.equal(x, y, message);
    }
};

assert.forward = function (fwd, pairs) {
    pairs.forEach(function (pair, lineno) {
        try {
            assert.equal(fwd(pair[0]), pair[1]);
        } catch (e) {
            e.message += '\nforward example ' + (1 + lineno);
            throw e;
        }
    });
};

assert.backward = function (bwd, pairs) {
    pairs.forEach(function (pair, lineno) {
        try {
            assert.equal(bwd(pair[1]), pair[0]);
        } catch (e) {
            e.message += '\nbackward example ' + (1 + lineno);
            throw e;
        }
    });
};

assert.inverses = function (fwd, bwd, items) {
    items.forEach(function (item, lineno) {
        try {
            assert.equal(bwd(fwd(item)), item);
        } catch (e) {
            e.message += '\ninverses example ' + (1 + lineno);
            throw e;
        }
    });
};

assert.injects = function (fwd, items) {
    var seen = {};
    items.forEach(function (item) {
        var result = fwd(item);
        assert(
            !_.has(seen, result),
            'duplicate result:' +
            '\n  ' + JSON.stringify(seen[result]) +
            '\n  ' + JSON.stringify(item) +
            '\nboth map to ' +
            '\n  ' + result);
        seen[result] = item;
    });
};

module.exports = assert;
<commit_msg>Drop support for custom assert.close tol<commit_after>'use strict';

var _ = require('lodash');

var TOL = 1e-8;

/** @constructor */
var AssertException = function (message) {
    this.message = message || '(unspecified)';
};

AssertException.prototype.toString = function () {
    return 'Assertion Failed: ' + this.message;
};

var assert = function (condition, message) {
    if (!condition) {
        throw new AssertException(message);
    }
};

assert.Exception = AssertException;

assert.equal = function (actual, expected, message) {
    assert(_.isEqual(actual, expected),
        (message || '') +
        '\n  actual = ' + JSON.stringify(actual) +
        '\n  expected = ' + JSON.stringify(expected));
};

assert.close = function (x, y, message) {
    message = message || 'Not close:';
    assert.equal(typeof x, typeof y);
    if (_.isNumber(x)) {
        assert(Math.abs(x - y) < TOL,
            message +
            '\n  actual = ' + JSON.stringify(x) +
            '\n  expected = ' + JSON.stringify(y));
    } else if (_.isArray(x)) {
        assert.equal(x.length, y.length, message + ' lengths differ');
        _.each(x, function (actual, pos) {
            var expected = y[pos];
            assert.close(actual, expected, message + ' [' + pos + ']');
        });
    } else if (_.isObject(x)) {
        assert.equal(_.keys(x).sort(), _.keys(y).sort(), ' keys differ');
        _.each(x, function (actual, key) {
            var expected = y[key];
            assert.close(actual, expected, message + ' [' + key + ']');
        });
    } else {
        assert.equal(x, y, message);
    }
};

assert.forward = function (fwd, pairs) {
    pairs.forEach(function (pair, lineno) {
        try {
            assert.equal(fwd(pair[0]), pair[1]);
        } catch (e) {
            e.message += '\nforward example ' + (1 + lineno);
            throw e;
        }
    });
};

assert.backward = function (bwd, pairs) {
    pairs.forEach(function (pair, lineno) {
        try {
            assert.equal(bwd(pair[1]), pair[0]);
        } catch (e) {
            e.message += '\nbackward example ' + (1 + lineno);
            throw e;
        }
    });
};

assert.inverses = function (fwd, bwd, items) {
    items.forEach(function (item, lineno) {
        try {
            assert.equal(bwd(fwd(item)), item);
        } catch (e) {
            e.message += '\ninverses example ' + (1 + lineno);
            throw e;
        }
    });
};

assert.injects = function (fwd, items) {
    var seen = {};
    items.forEach(function (item) {
        var result = fwd(item);
        assert(
            !_.has(seen, result),
            'duplicate result:' +
            '\n  ' + JSON.stringify(seen[result]) +
            '\n  ' + JSON.stringify(item) +
            '\nboth map to ' +
            '\n  ' + result);
        seen[result] = item;
    });
};

module.exports = assert;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

var directives = angular.module('directives', []);
directives.directive('focusMe', ["$timeout", function($timeout) {
    return {
        scope: { trigger: '@focusMe' },
        link: function(scope, element) {
            scope.$watch('trigger', function(value) {
                if(value === "true") {
                    $timeout(function() {
                        element[0].focus();
                    });
                }
            });
        }
    };
}]).directive('isMarkitup', ['$http', function($http) {
    return {
        restrict: 'A',
        scope: {
            show:  '=ngShow',
            html:  '=isModelHtml',
            model: '=ngModel'
        },
        link: function(scope, element, attrs) {
            var settings = $.extend({
                    resizeHandle:false,
                    scrollContainer:'#main-content .details:first',
                    afterInsert: function() {
                        element.triggerHandler('input');
                    }
                },
                textileSettings);
            var markitup = element.markItUp(settings);
            var container = markitup.parents('.markItUp');
            container.hide();

            scope.$watch('show', function(value) {
                if (value === true){
                    container.show();
                    setTimeout(function(){
                        element[0].focus();
                    }, 50);
                } else {
                    container.hide();
                }
            });
            element.bind('blur', function() {
                var val = element.val();
                scope.$apply($http({
                    method: 'POST',
                    url: 'textileParser',
                    headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
                    data: 'data='+val
                }).success(function(data) {
                    scope.html = data;
                }));
            });
        }
    };
}]).directive('showValidation', ['$compile', '$rootScope', function($compile, $rootScope) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            scope.$watch(function() {
                return scope.$eval(attrs.name);
            }, function(form, oldForm) {
                var inputs = element.find('input[ng-model]:not([validation-watched]), textarea[ng-model]:not([validation-watched])');
                angular.forEach(inputs, function(it) {
                    var input = angular.element(it);
                    input.attr('validation-watched','');
                    var container = input.parent();
                    if (container.hasClass('input-group')) {
                        container = container.parent();
                    }
                    var inputModel = form[input.attr('name')];
                    scope.$watch(function() {
                        return inputModel.$invalid && (inputModel.$dirty || inputModel.$touched);
                    }, function(newIsInvalid, oldIsInvalid) {
                        if (newIsInvalid && !oldIsInvalid) {
                            var childScope = scope.$new();
                            childScope.inputModel = inputModel;
                            childScope.errorMessages = function(errors) {
                                return  _.transform(errors, function(errorMessages, value, key) {
                                    if (value) {
                                        var name = input.siblings("label[for='" + input.attr('name') + "']").text();
                                        var errorMessage = '';
                                        if (key == 'required') {
                                            errorMessage = $rootScope.message('default.blank.message');
                                        } else if (key == 'min') {
                                            errorMessage = $rootScope.message('default.invalid.min.message', ['', '', '', input.attr(key)]);
                                        } else if (key == 'max') {
                                            errorMessage = $rootScope.message('default.invalid.max.message', ['', '', '', input.attr(key)]);
                                        } else if (key == 'minlength') {
                                            errorMessage = $rootScope.message('default.invalid.min.size.message', ['', '', '', input.attr('ng-' + key)]);
                                        } else if (key == 'maxlength') {
                                            errorMessage = $rootScope.message('default.invalid.max.size.message', ['', '', '', input.attr('ng-' + key)]);
                                        } else if (key == 'pattern') {
                                            errorMessage = $rootScope.message('default.doesnt.match.message', ['', '', '', input.attr('ng-' + key)]);
                                        } else if (key == 'url') {
                                            errorMessage = $rootScope.message('default.invalid.url.message');
                                        } else if (key == 'email') {
                                            errorMessage = $rootScope.message('default.invalid.email.message');
                                        } else if (key == 'number') {
                                            errorMessage = $rootScope.message('typeMismatch.java.lang.Integer');
                                        } else if (key == 'match') {
                                            errorMessage = $rootScope.message('is.user.password.check');
                                        } else if (key == 'unique') {
                                            errorMessage = $rootScope.message('default.unique.message');
                                        }
                                        errorMessages.push(errorMessage);
                                    }
                                }, []);
                            };
                            childScope.input = input;
                            container.addClass('has-error');
                            var template = '
{{ errorMessage }}
';
                            var compiledTemplate = angular.element($compile(template)(childScope));
                            container.append(compiledTemplate);
                        } else if (!newIsInvalid && oldIsInvalid) {
                            container.removeClass('has-error');
                            container.find('.help-block').remove();
                        }
                    });
                });
            }, true);
        }
    }
}]).directive('notMatch', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        scope: {
            notMatch: '='
        },
        link: function(scope, elem, attrs, ngModel) {
            ngModel.$validators.notMatch = function(modelValue, viewValue) {
                var value = modelValue || viewValue;
                var notMatch = scope.notMatch;
                return value != notMatch;
            };
            scope.$watch('notMatch', function() {
                ngModel.$validate();
            });
        }
    };
}).directive('isMatch', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        scope: {
            isMatch: '='
        },
        link: function(scope, elem, attrs, ngModel) {
            ngModel.$validators.isMatch = function(modelValue, viewValue) {
                var value = modelValue || viewValue;
                var isMatch = scope.isMatch;
                return value === isMatch;
            };
            scope.$watch('isMatch', function() {
                ngModel.$validate();
            });
        }
    };
}).directive('formAutofillFix', ['$timeout', function($timeout) {
    return function (scope, element, attrs) {
        element.prop('method', 'post');
        if (attrs.ngSubmit) {
            $timeout(function () {
                element
                    .unbind('submit')
                    .bind('submit', function (event) {
                        event.preventDefault();
                        element
                            .find('input, textarea, select')
                            .trigger('input')
                            .trigger('change')
                            .trigger('keydown');
                        scope.$apply(attrs.ngSubmit);
                    });
            });
        }
    };
}]).directive('ellipsis', [function () {
    return {
        required: 'ngModel', // explicit ng-model is required even in presence ng-bind-html because it creates the ng-model only when the field is updated
        restrict: 'A',
        priority: 100,
        scope:{
            ngModel:'='
        },
        link: function (scope, element) {
            scope.$watch(function() {
                return scope.ngModel + element.width(); // ugly hack but it seems to work
            }, function() {
                element.data('jqae', null);
                element.ellipsis();
            });
        }
    };
}]).directive('timeago', [function() {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.data('hasTimeago', false);
            scope.$watch("", function(value) {
                // apply only once
                if (!element.data('hasTimeago')) {
                    element.data('hasTimeago',true);
                    element.timeago();
                }
            });
        }
    };
}]).directive('at', [function() {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.data('hasAt', false);
            scope.$watch(function() {
                // Cannot use isolated scope (e.g. scope { at: '=' } because there are already isolated scope on the element)
                return scope.$eval(attrs.at);
            }, function(newOptions) {
                if (element.data('hasAt')) {
                    // recreate if options has changed, eg. promise completed for data
                    element.atwho('destroy');
                } else {
                    element.data('hasAt', true);
                }
                element.atwho(newOptions);
            }, true);
        }
    };
}]).directive('capitalize', function() {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, modelCtrl) {
                var capitalize = function(inputValue) {
                    if(inputValue == undefined) inputValue = '';
                    if(attrs.noSpace){
                        inputValue = inputValue.replace(/[\s]/g, '');
                    }
                    var capitalized = inputValue.toUpperCase();
                    if(capitalized !== inputValue) {
                        modelCtrl.$setViewValue(capitalized);
                        modelCtrl.$render();
                    }
                    return capitalized;
                };
                modelCtrl.$parsers.push(capitalize);
                capitalize(scope[attrs.ngModel]);
            }
        };
}).directive('btnModel', function() {
    return {
        restrict: 'C',
        require: 'ngModel',
        link: function(scope, element, attrs, modelCtrl) {
            element.on('mousedown', function() {
                modelCtrl.$setDirty();
                modelCtrl.$setTouched();
            });
        }
    };
}).directive('selectOnFocus', function () {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
}).directive('isProgress',['$rootScope', '$timeout', '$http', function($rootScope, $timeout, $http) {
    return {
        restrict: 'E',
        scope: {
            start:'='
        },
        templateUrl: 'is.progress.html',
        link: function (scope, element, attrs) {
            var status;

            scope.progress = {
                value: -1,
                label: "",
                type:'primary'
            };

            scope.$watch('start', function( value ) {
                stopProgress();
                if (value === true){
                    $timeout(progress, 500);
                }
            });

            var progress = function() {
                $http({
                    method: "get",
                    url: $rootScope.serverUrl + "/progress"
                }).then(function (response) {
                    scope.progress = response.data;
                    if (!response.data.error && !response.data.complete) {
                        status = $timeout(progress, 500);
                    }
                    if (response.data.error){
                        scope.progress.type = 'danger';
                    }else if (response.data.complete){
                        scope.progress.type = 'success';
                    }
                }, function(){
                    scope.progress.type = 'danger';
                    scope.progress.label = scope.message(attrs.errorMessage?attrs.errorMessage:'todo.is.ui.error');
                    scope.progress.value = 100;
                });
            };

            var stopProgress = function(){
                if (angular.isDefined(status)) {
                    $timeout.cancel(status);
                    status = undefined;
                }
            };

            element.on('$destroy', function() {
                stopProgress();
            });
        }
    };
}]);<commit_msg>Don't validate ui-select inputs<commit_after>/*
 * Copyright (c) 2014 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

var directives = angular.module('directives', []);
directives.directive('focusMe', ["$timeout", function($timeout) {
    return {
        scope: { trigger: '@focusMe' },
        link: function(scope, element) {
            scope.$watch('trigger', function(value) {
                if(value === "true") {
                    $timeout(function() {
                        element[0].focus();
                    });
                }
            });
        }
    };
}]).directive('isMarkitup', ['$http', function($http) {
    return {
        restrict: 'A',
        scope: {
            show:  '=ngShow',
            html:  '=isModelHtml',
            model: '=ngModel'
        },
        link: function(scope, element, attrs) {
            var settings = $.extend({
                    resizeHandle:false,
                    scrollContainer:'#main-content .details:first',
                    afterInsert: function() {
                        element.triggerHandler('input');
                    }
                },
                textileSettings);
            var markitup = element.markItUp(settings);
            var container = markitup.parents('.markItUp');
            container.hide();

            scope.$watch('show', function(value) {
                if (value === true){
                    container.show();
                    setTimeout(function(){
                        element[0].focus();
                    }, 50);
                } else {
                    container.hide();
                }
            });
            element.bind('blur', function() {
                var val = element.val();
                scope.$apply($http({
                    method: 'POST',
                    url: 'textileParser',
                    headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
                    data: 'data='+val
                }).success(function(data) {
                    scope.html = data;
                }));
            });
        }
    };
}]).directive('showValidation', ['$compile', '$rootScope', function($compile, $rootScope) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            scope.$watch(function() {
                return scope.$eval(attrs.name);
            }, function(form, oldForm) {
                var inputs = element.find('input[ng-model]:not([validation-watched]):not(.ui-select-search), textarea[ng-model]:not([validation-watched])');
                angular.forEach(inputs, function(it) {
                    var input = angular.element(it);
                    input.attr('validation-watched','');
                    var container = input.parent();
                    if (container.hasClass('input-group')) {
                        container = container.parent();
                    }
                    var inputModel = form[input.attr('name')];
                    scope.$watch(function() {
                        return inputModel.$invalid && (inputModel.$dirty || inputModel.$touched);
                    }, function(newIsInvalid, oldIsInvalid) {
                        if (newIsInvalid && !oldIsInvalid) {
                            var childScope = scope.$new();
                            childScope.inputModel = inputModel;
                            childScope.errorMessages = function(errors) {
                                return _.transform(errors, function(errorMessages, value, key) {
                                    if (value) {
                                        var name = input.siblings("label[for='" + input.attr('name') + "']").text();
                                        var errorMessage = '';
                                        if (key == 'required') {
                                            errorMessage = $rootScope.message('default.blank.message');
                                        } else if (key == 'min') {
                                            errorMessage = $rootScope.message('default.invalid.min.message', ['', '', '', input.attr(key)]);
                                        } else if (key == 'max') {
                                            errorMessage = $rootScope.message('default.invalid.max.message', ['', '', '', input.attr(key)]);
                                        } else if (key == 'minlength') {
                                            errorMessage = $rootScope.message('default.invalid.min.size.message', ['', '', '', input.attr('ng-' + key)]);
                                        } else if (key == 'maxlength') {
                                            errorMessage = $rootScope.message('default.invalid.max.size.message', ['', '', '', input.attr('ng-' + key)]);
                                        } else if (key == 'pattern') {
                                            errorMessage = $rootScope.message('default.doesnt.match.message', ['', '', '', input.attr('ng-' + key)]);
                                        } else if (key == 'url') {
                                            errorMessage = $rootScope.message('default.invalid.url.message');
                                        } else if (key == 'email') {
                                            errorMessage = $rootScope.message('default.invalid.email.message');
                                        } else if (key == 'number') {
                                            errorMessage = $rootScope.message('typeMismatch.java.lang.Integer');
                                        } else if (key == 'match') {
                                            errorMessage = $rootScope.message('is.user.password.check');
                                        } else if (key == 'unique') {
                                            errorMessage = $rootScope.message('default.unique.message');
                                        }
                                        errorMessages.push(errorMessage);
                                    }
                                }, []);
                            };
                            childScope.input = input;
                            container.addClass('has-error');
                            var template = '
{{ errorMessage }}
';
                            var compiledTemplate = angular.element($compile(template)(childScope));
                            container.append(compiledTemplate);
                        } else if (!newIsInvalid && oldIsInvalid) {
                            container.removeClass('has-error');
                            container.find('.help-block').remove();
                        }
                    });
                });
            }, true);
        }
    }
}]).directive('notMatch', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        scope: {
            notMatch: '='
        },
        link: function(scope, elem, attrs, ngModel) {
            ngModel.$validators.notMatch = function(modelValue, viewValue) {
                var value = modelValue || viewValue;
                var notMatch = scope.notMatch;
                return value != notMatch;
            };
            scope.$watch('notMatch', function() {
                ngModel.$validate();
            });
        }
    };
}).directive('isMatch', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        scope: {
            isMatch: '='
        },
        link: function(scope, elem, attrs, ngModel) {
            ngModel.$validators.isMatch = function(modelValue, viewValue) {
                var value = modelValue || viewValue;
                var isMatch = scope.isMatch;
                return value === isMatch;
            };
            scope.$watch('isMatch', function() {
                ngModel.$validate();
            });
        }
    };
}).directive('formAutofillFix', ['$timeout', function($timeout) {
    return function (scope, element, attrs) {
        element.prop('method', 'post');
        if (attrs.ngSubmit) {
            $timeout(function () {
                element
                    .unbind('submit')
                    .bind('submit', function (event) {
                        event.preventDefault();
                        element
                            .find('input, textarea, select')
                            .trigger('input')
                            .trigger('change')
                            .trigger('keydown');
                        scope.$apply(attrs.ngSubmit);
                    });
            });
        }
    };
}]).directive('ellipsis', [function () {
    return {
        required: 'ngModel', // explicit ng-model is required even in presence ng-bind-html because it creates the ng-model only when the field is updated
        restrict: 'A',
        priority: 100,
        scope:{
            ngModel:'='
        },
        link: function (scope, element) {
            scope.$watch(function() {
                return scope.ngModel + element.width(); // ugly hack but it seems to work
            }, function() {
                element.data('jqae', null);
                element.ellipsis();
            });
        }
    };
}]).directive('timeago', [function() {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.data('hasTimeago', false);
            scope.$watch("", function(value) {
                // apply only once
                if (!element.data('hasTimeago')) {
                    element.data('hasTimeago',true);
                    element.timeago();
                }
            });
        }
    };
}]).directive('at', [function() {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.data('hasAt', false);
            scope.$watch(function() {
                // Cannot use isolated scope (e.g. scope { at: '=' } because there are already isolated scope on the element)
                return scope.$eval(attrs.at);
            }, function(newOptions) {
                if (element.data('hasAt')) {
                    // recreate if options has changed, eg. promise completed for data
                    element.atwho('destroy');
                } else {
                    element.data('hasAt', true);
                }
                element.atwho(newOptions);
            }, true);
        }
    };
}]).directive('capitalize', function() {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, modelCtrl) {
                var capitalize = function(inputValue) {
                    if(inputValue == undefined) inputValue = '';
                    if(attrs.noSpace){
                        inputValue = inputValue.replace(/[\s]/g, '');
                    }
                    var capitalized = inputValue.toUpperCase();
                    if(capitalized !== inputValue) {
                        modelCtrl.$setViewValue(capitalized);
                        modelCtrl.$render();
                    }
                    return capitalized;
                };
                modelCtrl.$parsers.push(capitalize);
                capitalize(scope[attrs.ngModel]);
            }
        };
}).directive('btnModel', function() {
    return {
        restrict: 'C',
        require: 'ngModel',
        link: function(scope, element, attrs, modelCtrl) {
            element.on('mousedown', function() {
                modelCtrl.$setDirty();
                modelCtrl.$setTouched();
            });
        }
    };
}).directive('selectOnFocus', function () {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
}).directive('isProgress',['$rootScope', '$timeout', '$http', function($rootScope, $timeout, $http) {
    return {
        restrict: 'E',
        scope: {
            start:'='
        },
        templateUrl: 'is.progress.html',
        link: function (scope, element, attrs) {
            var status;

            scope.progress = {
                value: -1,
                label: "",
                type:'primary'
            };

            scope.$watch('start', function( value ) {
                stopProgress();
                if (value === true){
                    $timeout(progress, 500);
                }
            });

            var progress = function() {
                $http({
                    method: "get",
                    url: $rootScope.serverUrl + "/progress"
                }).then(function (response) {
                    scope.progress = response.data;
                    if (!response.data.error && !response.data.complete) {
                        status = $timeout(progress, 500);
                    }
                    if (response.data.error){
                        scope.progress.type = 'danger';
                    }else if (response.data.complete){
                        scope.progress.type = 'success';
                    }
                }, function(){
                    scope.progress.type = 'danger';
                    scope.progress.label = scope.message(attrs.errorMessage?attrs.errorMessage:'todo.is.ui.error');
                    scope.progress.value = 100;
                });
            };

            var stopProgress = function(){
                if (angular.isDefined(status)) {
                    $timeout.cancel(status);
                    status = undefined;
                }
            };

            element.on('$destroy', function() {
                stopProgress();
            });
        }
    };
}]);<|endoftext|>


<commit_before>var $ = require('jquery');

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var Enemy = require("./enemies.js");
var Bluecifer = require('./bluecifer');

var bluecifer = new Bluecifer (150, 150, 50, 41);

$('#game-over').css('visibility', 'visible');

var themeSong = document.getElementById("theme-song");
var celebration = document.getElementById("celebration");

var enemy = new Enemy();
var enemy2 = new Enemy();
var enemy3 = new Enemy();

var collisionCanHappen = true;

function drawAirport () {
  var image = new Image();
  image.src = "IMGS/dia-photo.jpg";
  var airport = {};
  airport.x = 150;
  airport.y = 340;
  airport.width = 30;
  airport.height = 30;
  ctx.drawImage(image, airport.x, airport.y, airport.width, airport.height);
  airportCollision(airport, bluecifer);
  return this;
}

function newEnemy () {
  enemy.draw(ctx);
  collision(enemy, bluecifer);
  enemy.moveLeftRandom();
}

function newEnemy2 () {
  enemy2.draw(ctx);
  collision(enemy2, bluecifer);
  setTimeout(function() {
    enemy2.moveLeftRandom();
    return enemy2;
  }, 3000);
}

function newEnemy3 () {
  enemy3.draw(ctx);
  collision(enemy3, bluecifer);
  setTimeout(function() {
    enemy3.moveLeftRandom();
    return enemy3;
  }, 6000);
}

function collision(a, b) {
  if (((a.y + a.height) < (b.y)) || (a.y > (b.y + b.height)) || ((a.x + a.width) < b.x) || (a.x > (b.x + b.width)) || collisionCanHappen === false) {
  //if there is no collision
  }
  else {
    themeSong.pause();
    youAreDead();
    setTimeout(function() {
      $('#game-over').css('visibility', 'visible');
    }, 5000);
    resetGame();
  }
} //end of collision function

function airportCollision (a, b) {
  if (((a.y + a.height) < (b.y)) || (a.y > (b.y + b.height)) || ((a.x + a.width) < b.x) || (a.x > (b.x + b.width))) {
  //if there is no collision
  }
  else {
    themeSong.pause();
    celebration.play();
    $("#message-center").text("You win!");
    resetGame();
  }
} //end of airportCollision function

function repeat () {
  setTimeout(function() {
    requestAnimationFrame(repeat);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    bluecifer.draw(ctx);
    bluecifer.gravity();
    newEnemy();
    newEnemy2();
    newEnemy3();
    detectFloorCollision();
  }, 1000 / 50);
    keepScore();
} //end of big repeat function

$(document).on("click", function () {
  themeSong.play();
  $('#game-over').css('visibility', 'hidden');
  repeat();
});

var scoreCounter = 0;

function keepScore() {
    var currentScore = scoreCounter++;
    if (currentScore <= 100){
   $('#game-score').text("000" + currentScore);
 }else if (currentScore <= 1000){
  $('#game-score').text("00" + currentScore);
}else if (currentScore <= 10000){
  $('#game-score').text("0" + currentScore);
  drawAirport();
}else{
  $('#game-score').text(currentScore);
  }
}

function detectFloorCollision () {
  if (bluecifer.y > 350) {
    themeSong.pause();
    youAreDead();
    resetGame();
    bluecifer.y = 300;
  }
}

$(document).on("keydown", function (key) {
  if (key.which === 32) {
    if ($('#game-over').css('visibility', 'hidden')) {
      bluecifer.moveUp();
      detectCeilingCollision();
    }
    else {
      resetGame();
    }
  } //end of if statement for space bar
  else if (key.which === 13) {
    themeSong.pause();
  } // end of if statement for enter key
  else if (key.which === 85 && scoreCounter === 0) {
    var code = prompt("Enter cheat code");
    cheat(code);
  } // end of if statement for u key
}); //end of entire function

function detectCeilingCollision () {
  if (bluecifer.y < 0) {
    bluecifer.y = bluecifer.y + 20;
  }
}

function cheat (code) {
  if (code === "dogs") {
    collisionCanHappen = false;
    alert("Cheat mode activated!");
  }
  else {
    alert("Nope, wrong code!");
  }
}

function resetGame () {
  // alert("Game over! Your score was " + scoreCounter);
  location.reload();
  $('#game-over').css('visibility', 'hidden');
  repeat();
}

function youAreDead () {
  $("#message-center").text("Game Over! Your score was " + scoreCounter);
}
<commit_msg>got rid  of setTimeout for collision death to improve sequence flow<commit_after>var $ = require('jquery');

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var Enemy = require("./enemies.js");
var Bluecifer = require('./bluecifer');

var bluecifer = new Bluecifer (150, 150, 50, 41);

$('#game-over').css('visibility', 'visible');

var themeSong = document.getElementById("theme-song");
var celebration = document.getElementById("celebration");

var enemy = new Enemy();
var enemy2 = new Enemy();
var enemy3 = new Enemy();

var collisionCanHappen = true;

function drawAirport () {
  var image = new Image();
  image.src = "IMGS/dia-photo.jpg";
  var airport = {};
  airport.x = 150;
  airport.y = 340;
  airport.width = 30;
  airport.height = 30;
  ctx.drawImage(image, airport.x, airport.y, airport.width, airport.height);
  airportCollision(airport, bluecifer);
  return this;
}

function newEnemy () {
  enemy.draw(ctx);
  collision(enemy, bluecifer);
  enemy.moveLeftRandom();
}

function newEnemy2 () {
  enemy2.draw(ctx);
  collision(enemy2, bluecifer);
  setTimeout(function() {
    enemy2.moveLeftRandom();
    return enemy2;
  }, 3000);
}

function newEnemy3 () {
  enemy3.draw(ctx);
  collision(enemy3, bluecifer);
  setTimeout(function() {
    enemy3.moveLeftRandom();
    return enemy3;
  }, 6000);
}

function collision(a, b) {
  if (((a.y + a.height) < (b.y)) || (a.y > (b.y + b.height)) || ((a.x + a.width) < b.x) || (a.x > (b.x + b.width)) || collisionCanHappen === false) {
  //if there is no collision
  }
  else {
    themeSong.pause();
    youAreDead();
    $('#game-over').css('visibility', 'visible');
    resetGame();
  }
} //end of collision function

function airportCollision (a, b) {
  if (((a.y + a.height) < (b.y)) || (a.y > (b.y + b.height)) || ((a.x + a.width) < b.x) || (a.x > (b.x + b.width))) {
  //if there is no collision
  }
  else {
    themeSong.pause();
    celebration.play();
    $("#message-center").text("You win!");
    resetGame();
  }
} //end of airportCollision function

function repeat () {
  setTimeout(function() {
    requestAnimationFrame(repeat);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    bluecifer.draw(ctx);
    bluecifer.gravity();
    newEnemy();
    newEnemy2();
    newEnemy3();
    detectFloorCollision();
  }, 1000 / 50);
    keepScore();
} //end of big repeat function

$(document).on("click", function () {
  themeSong.play();
  $('#game-over').css('visibility', 'hidden');
  repeat();
});

var scoreCounter = 0;

function keepScore() {
    var currentScore = scoreCounter++;
    if (currentScore <= 100){
   $('#game-score').text("000" + currentScore);
 }else if (currentScore <= 1000){
  $('#game-score').text("00" + currentScore);
}else if (currentScore <= 10000){
  $('#game-score').text("0" + currentScore);
  drawAirport();
}else{
  $('#game-score').text(currentScore);
  }
}

function detectFloorCollision () {
  if (bluecifer.y > 350) {
    themeSong.pause();
    youAreDead();
    resetGame();
    bluecifer.y = 300;
  }
}

$(document).on("keydown", function (key) {
  if (key.which === 32) {
    if ($('#game-over').css('visibility', 'hidden')) {
      bluecifer.moveUp();
      detectCeilingCollision();
    }
    else {
      resetGame();
    }
  } //end of if statement for space bar
  else if (key.which === 13) {
    themeSong.pause();
  } // end of if statement for enter key
  else if (key.which === 85 && scoreCounter === 0) {
    var code = prompt("Enter cheat code");
    cheat(code);
  } // end of if statement for u key
}); //end of entire function

function detectCeilingCollision () {
  if (bluecifer.y < 0) {
    bluecifer.y = bluecifer.y + 20;
  }
}

function cheat (code) {
  if (code === "dogs") {
    collisionCanHappen = false;
    alert("Cheat mode activated!");
  }
  else {
    alert("Nope, wrong code!");
  }
}

function resetGame () {
  // alert("Game over! Your score was " + scoreCounter);
  location.reload();
  $('#game-over').css('visibility', 'hidden');
  repeat();
}

function youAreDead () {
  $("#message-center").text("Game Over! Your score was " + scoreCounter);
}
<|endoftext|>


<commit_before>module.exports = function(config) {
    config.set({
        frameworks: ['jasmine'],

        files: [
            'node_modules/angular/angular.min.js',
            'node_modules/angular-mocks/angular-mocks.js',
            'spec/*Spec.js',
            'src/hyper-content-for.js'
        ]
    });
};
<commit_msg>Launch Chrome and PhantomJS by default in Karma<commit_after>module.exports = function(config) {
    config.set({
        frameworks: ['jasmine'],

        files: [
            'node_modules/angular/angular.min.js',
            'node_modules/angular-mocks/angular-mocks.js',
            'spec/*Spec.js',
            'src/hyper-content-for.js'
        ],

        browsers: ['Chrome', 'PhantomJS']
    });
};
<|endoftext|>


<commit_before>/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/*
 * Copyright 2013 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function loadMovie(path, reportFrames) {
  var movieReady = new Promise;
  movieReady.then(function() { sendResponse(); });

  var onFrameCallback = null;
  if (reportFrames) {
    var i = 0, frame = 0;
    onFrameCallback = function () {
      while (i < reportFrames.length && frame >= reportFrames[i]) {
        movieReady.then(sendResponse.bind(null, {
          index: i,
          frame: frame,
          snapshot: getCanvasData()
        }));
        i++;
      }
      frame++;
    };
  }

  createAVM2(builtinPath, playerGlobalPath, EXECUTION_MODE.INTERPRET, EXECUTION_MODE.COMPILE, function (avm2) {
    function loaded() { movieReady.resolve(); }
    function terminate() {
      ignoreAdanvances = true;
      // cleaning up
      if (!movieReady.resolved) { // movieReady needs to be resolved
        movieReady.resolve();
      }
      if (advanceTimeout) { // invoke current timeout
        clearTimeout(advanceTimeout);
        advanceCallback();
      }
      // reports unreported frames
      while (reportFrames && i < reportFrames.length) {
        onFrameCallback();
      }
    }

    FileLoadingService.baseUrl = path;
    new BinaryFileReader(path).readAll(null, function(buffer) {
      if (!buffer) {
        throw "Unable to open the file " + SWF_PATH + ": " + error;
      }
      SWF.embed(buffer, document, document.getElementById("stage"), {
        onComplete: loaded,
        onAfterFrame: onFrameCallback,
        onTerminated: terminate
      });
    });
  });
}

var sanityTests = {
  tests: [],
  push: function () {
    this.tests.push.apply(this.tests, arguments);
    this.onload();
  },
  onload: null
};

function loadScripts(files) {
  sanityTests.onload = next;

  var i = 0;
  function next() {
    if (i >= files.length) {
      return runSanityTests(sanityTests.tests);
    }
    var script = document.createElement('script');
    script.src = files[i++];
    document.getElementsByTagName('head')[0].appendChild(script);
  }
  next();
}

function runSanityTests(tests) {
  createAVM2(builtinPath, playerGlobalPath, EXECUTION_MODE.INTERPRET, EXECUTION_MODE.COMPILE, function (avm2) {
    sendResponse();
    for (var i = 0; i < tests.length; i++) {
      var failed = false;
      try {
        tests[i]({
          info: function (m) {
            console.info(m);
          },
          error: function (m) {
            console.error(m);
            failed = true;
          }
        }, avm2);
      } catch (ex) {
        failed = true;
      }
      sendResponse({index: i, failure: failed});
    }
  });
}

var FileLoadingService = {
  createSession: function () {
    return {
      open: function (request) {
        var self = this;
        var base = FileLoadingService.baseUrl || '';
        base = base.lastIndexOf('/') >= 0 ? base.substring(0, base.lastIndexOf('/') + 1) : '';
        var path = base ? base + request.url : request.url;
        console.log('FileLoadingService: loading ' + path);
        new BinaryFileReader(path).readAsync(
          function (data, progress) {
            self.onprogress(data, {bytesLoaded: progress.loaded, bytesTotal: progress.total});
          },
          function (e) { self.onerror(e); },
          self.onopen,
          self.onclose);
      }
    };
  }
};

var traceMessages = '';
natives.print = function() {
   return function(s) {
     traceMessages += s + '\n';
   };
};

function sendResponse(data) {
  window.parent.postMessage({
    type: 'test-response',
    result: data
  }, '*');
}

function getCanvasData() {
  var canvas = document.getElementsByTagName('canvas')[0];
  return canvas.toDataURL('image/png');
}

var mouseOutside = true;

function sendMouseEvent(type, x, y) {
  var isMouseMove = type == 'mousemove';
  var canvas = document.getElementsByTagName('canvas')[0];
  var e = document.createEvent('MouseEvents');
  e.initMouseEvent(type, true, !isMouseMove,
                   document.defaultView, isMouseMove ? 0 : 1,
                   x, y, x, y,
                   false, false, false, false, 0, canvas);
  canvas.dispatchEvent(e);
}

var advanceTimeout = null, ignoreAdanvances = false;

function advanceCallback() {
  advanceTimeout = null;
  sendResponse();
}

window.addEventListener('message', function (e) {
  var data = e.data;
  if (typeof data !== 'object' || data.type !== 'test-message')
    return;
  switch (data.topic) {
  case 'load':
    loadMovie(data.path, data.reportFrames);
    break;
  case 'js':
    loadScripts(data.files);
    break;
  case 'advance':
    if (ignoreAdanvances) {
      advanceCallback();
      break;
    }
    var delay = data.args[0];
    advanceTimeout = setTimeout(advanceCallback, delay);
    break;
  case 'mouse-move':
    if (mouseOutside) {
      sendMouseEvent('mouseover', data.args[0], data.args[1]);
      mouseOutside = false;
    }
    sendMouseEvent('mousemove', data.args[0], data.args[1]);
    break;
  case 'mouse-press':
    sendMouseEvent('mousedown', data.args[0], data.args[1]);
    sendMouseEvent('click', data.args[0], data.args[1]);
    break;
  case 'mouse-release':
    sendMouseEvent('mouseup', data.args[0], data.args[1]);
    break;
  case 'get-trace':
    sendResponse(traceMessages);
    break;
  case 'get-image':
    sendResponse(getCanvasData());
    break;
  }
});
<commit_msg>Trying to fix DisplayObject testing<commit_after>/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/*
 * Copyright 2013 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function loadMovie(path, reportFrames) {
  var movieReady = new Promise;
  movieReady.then(function() { sendResponse(); });

  var onFrameCallback = null;
  if (reportFrames) {
    var i = 0, frame = 0;
    onFrameCallback = function () {
      while (i < reportFrames.length && frame >= reportFrames[i]) {
        var snapshot = getCanvasData();
        movieReady.then(sendResponse.bind(null, {
          index: i,
          frame: frame,
          snapshot: snapshot
        }));
        i++;
      }
      frame++;
    };
  }

  createAVM2(builtinPath, playerGlobalPath, EXECUTION_MODE.INTERPRET, EXECUTION_MODE.COMPILE, function (avm2) {
    function loaded() { movieReady.resolve(); }
    function terminate() {
      ignoreAdanvances = true;
      // cleaning up
      if (!movieReady.resolved) { // movieReady needs to be resolved
        movieReady.resolve();
      }
      if (advanceTimeout) { // invoke current timeout
        clearTimeout(advanceTimeout);
        advanceCallback();
      }
      // reports unreported frames
      while (reportFrames && i < reportFrames.length) {
        onFrameCallback();
      }
    }

    FileLoadingService.baseUrl = path;
    new BinaryFileReader(path).readAll(null, function(buffer) {
      if (!buffer) {
        throw "Unable to open the file " + SWF_PATH + ": " + error;
      }
      SWF.embed(buffer, document, document.getElementById("stage"), {
        onComplete: loaded,
        onAfterFrame: onFrameCallback,
        onTerminated: terminate
      });
    });
  });
}

var sanityTests = {
  tests: [],
  push: function () {
    this.tests.push.apply(this.tests, arguments);
    this.onload();
  },
  onload: null
};

function loadScripts(files) {
  sanityTests.onload = next;

  var i = 0;
  function next() {
    if (i >= files.length) {
      return runSanityTests(sanityTests.tests);
    }
    var script = document.createElement('script');
    script.src = files[i++];
    document.getElementsByTagName('head')[0].appendChild(script);
  }
  next();
}

function runSanityTests(tests) {
  createAVM2(builtinPath, playerGlobalPath, EXECUTION_MODE.INTERPRET, EXECUTION_MODE.COMPILE, function (avm2) {
    sendResponse();
    for (var i = 0; i < tests.length; i++) {
      var failed = false;
      try {
        tests[i]({
          info: function (m) {
            console.info(m);
          },
          error: function (m) {
            console.error(m);
            failed = true;
          }
        }, avm2);
      } catch (ex) {
        failed = true;
      }
      sendResponse({index: i, failure: failed});
    }
  });
}

var FileLoadingService = {
  createSession: function () {
    return {
      open: function (request) {
        var self = this;
        var base = FileLoadingService.baseUrl || '';
        base = base.lastIndexOf('/') >= 0 ? base.substring(0, base.lastIndexOf('/') + 1) : '';
        var path = base ? base + request.url : request.url;
        console.log('FileLoadingService: loading ' + path);
        new BinaryFileReader(path).readAsync(
          function (data, progress) {
            self.onprogress(data, {bytesLoaded: progress.loaded, bytesTotal: progress.total});
          },
          function (e) { self.onerror(e); },
          self.onopen,
          self.onclose);
      }
    };
  }
};

var traceMessages = '';
natives.print = function() {
   return function(s) {
     traceMessages += s + '\n';
   };
};

function sendResponse(data) {
  window.parent.postMessage({
    type: 'test-response',
    result: data
  }, '*');
}

function getCanvasData() {
  var canvas = document.getElementsByTagName('canvas')[0];
  return canvas.toDataURL('image/png');
}

var mouseOutside = true;

function sendMouseEvent(type, x, y) {
  var isMouseMove = type == 'mousemove';
  var canvas = document.getElementsByTagName('canvas')[0];
  var e = document.createEvent('MouseEvents');
  e.initMouseEvent(type, true, !isMouseMove,
                   document.defaultView, isMouseMove ? 0 : 1,
                   x, y, x, y,
                   false, false, false, false, 0, canvas);
  canvas.dispatchEvent(e);
}

var advanceTimeout = null, ignoreAdanvances = false;

function advanceCallback() {
  advanceTimeout = null;
  sendResponse();
}

window.addEventListener('message', function (e) {
  var data = e.data;
  if (typeof data !== 'object' || data.type !== 'test-message')
    return;
  switch (data.topic) {
  case 'load':
    loadMovie(data.path, data.reportFrames);
    break;
  case 'js':
    loadScripts(data.files);
    break;
  case 'advance':
    if (ignoreAdanvances) {
      advanceCallback();
      break;
    }
    var delay = data.args[0];
    advanceTimeout = setTimeout(advanceCallback, delay);
    break;
  case 'mouse-move':
    if (mouseOutside) {
      sendMouseEvent('mouseover', data.args[0], data.args[1]);
      mouseOutside = false;
    }
    sendMouseEvent('mousemove', data.args[0], data.args[1]);
    break;
  case 'mouse-press':
    sendMouseEvent('mousedown', data.args[0], data.args[1]);
    sendMouseEvent('click', data.args[0], data.args[1]);
    break;
  case 'mouse-release':
    sendMouseEvent('mouseup', data.args[0], data.args[1]);
    break;
  case 'get-trace':
    sendResponse(traceMessages);
    break;
  case 'get-image':
    sendResponse(getCanvasData());
    break;
  }
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import styled from 'styled-components';

import Icon from './Icon';

const BUTTON_SIZE = 30;

const CloseButton = styled.button`
  top: ${-BUTTON_SIZE / 2}px;
  right: ${-BUTTON_SIZE / 2}px;
  width: ${BUTTON_SIZE}px;
  height: ${BUTTON_SIZE}px;

  &:focus {
    outline: none;
  }
`;

CloseButton.defaultProps = {
  className: 'absolute circle shadow-subtle bg-white bold flex items-center cursor-pointer border border-white p0 hover-lime focus-lime'
};

const DialogBackdrop = styled.div`
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  opacity: 0.9;
`;

DialogBackdrop.defaultProps = {
  className: 'absolute bg-white'
};

const DialogContainer = styled.div`
  width: 100vw;
  maxWidth: 100%;
  height: 100%;
  padding: 25px 25px 40px;
  overflow-y: auto;
`;

DialogContainer.defaultProps = {
  className: 'flex'
};

const DialogBox = styled.div`
  width: 100%;
  maxWidth: ${(props) => props.width}px;
  margin: auto;
`;

DialogBox.defaultProps = {
  className: 'background bg-white rounded-3 shadow-subtle relative'
};

const DialogWrapper = styled.div`
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 1000;
`;

DialogWrapper.defaultProps = {
  className: 'fixed'
};

class Dialog extends React.Component {
  static propTypes = {
    children: React.PropTypes.node,
    closeable: React.PropTypes.bool,
    isOpen: React.PropTypes.bool,
    onRequestClose: React.PropTypes.func,
    width: React.PropTypes.number
  };

  static defaultProps = {
    closeable: true,
    isOpen: false,
    width: 500
  };

  constructor(initialProps) {
    super(initialProps);

    let rendered = false;
    let visible = false;

    if (initialProps.isOpen) {
      rendered = visible = true;
    }

    this.state = {
      rendered,
      visible
    };
  }

  componentDidMount() {
    document.documentElement.addEventListener('keydown', this.handleDocumentKeyDown, false);
  }

  componentWillUnmount() {
    document.documentElement.removeEventListener('keydown', this.handleDocumentKeyDown);
  }

  componentWillReceiveProps(nextProps) {
    // Opening the dialog
    if (!this.props.isOpen && nextProps.isOpen) {
      this.setState({ rendered: true }, () => {
        this.setState({ visible: true });
      });
    }

    // Closing the dialog
    if (this.props.isOpen && !nextProps.isOpen) {
      this.setState({ visible: false }, () => {
        // Give the animation some time to finish, then remove the dialog from
        // the DOM
        setTimeout(() => {
          this.setState({ rendered: false });
        }, 150);
      });
    }
  }

  maybeClose = (event) => {
    event.preventDefault();
    if (typeof this.props.onRequestClose === 'function') {
      this.props.onRequestClose();
    }
  };

  handleCloseClick = (event) => {
    this.maybeClose(event);
  };

  handleDocumentKeyDown = (event) => {
    // Close the dialog on hitting the escape key
    if (this.state.visible && event.keyCode === 27) {
      this.maybeClose(event);
    }
  };

  renderBackdrop() {
    if (!this.state.visible) {
      return;
    }

    return <DialogBackdrop />;
  }

  renderCloseButton() {
    if (!this.props.closeable) {
      return;
    }

    return (
      <CloseButton onClick={this.handleCloseClick}>
        <Icon className="mx-auto" icon="close" title="Close" />
      </CloseButton>
    );
  }

  renderDialog() {
    if (!this.state.visible) {
      return;
    }

    return (
      <DialogContainer>
        <DialogBox width={this.props.width}>
          {this.renderCloseButton()}
          {this.props.children}
        </DialogBox>
      </DialogContainer>
    );
  }

  render() {
    if (!this.state.rendered) {
      return null;
    }

    return (
      <DialogWrapper>
        {this.renderBackdrop()}
        <ReactCSSTransitionGroup transitionName="transition-slide-up" transitionEnterTimeout={150} transitionLeaveTimeout={300}>
          {this.renderDialog()}
        </ReactCSSTransitionGroup>
      </DialogWrapper>
    );
  }
}

export default Dialog;
<commit_msg>Improve dialog scroll behaviour in FF & Safari<commit_after>import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import styled from 'styled-components';

import Icon from './Icon';

const BUTTON_SIZE = 30;

const CloseButton = styled.button`
  top: ${-BUTTON_SIZE / 2}px;
  right: ${-BUTTON_SIZE / 2}px;
  width: ${BUTTON_SIZE}px;
  height: ${BUTTON_SIZE}px;

  &:focus {
    outline: none;
  }
`;

CloseButton.defaultProps = {
  className: 'absolute circle shadow-subtle bg-white bold flex items-center cursor-pointer border border-white p0 hover-lime focus-lime'
};

const DialogBackdrop = styled.div`
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  opacity: 0.9;
`;

DialogBackdrop.defaultProps = {
  className: 'absolute bg-white'
};

const DialogContainer = styled.div`
  width: 100vw;
  maxWidth: 100%;
  height: 100%;
  padding: 25px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;

  &:after {
    display: block;
    flex: 0 0 auto;
    height: 40px;
    content: '';
  }
`;
// NOTE: DialogContainer:after is a substitute for padding
// which would otherwise be applied, but is ignored by both
// Firefox and Safari!

DialogContainer.defaultProps = {
  className: 'flex flex-column'
};

const DialogBox = styled.div`
  width: 100%;
  maxWidth: ${(props) => props.width}px;
  margin: auto;
`;

DialogBox.defaultProps = {
  className: 'background bg-white rounded-3 shadow-subtle relative'
};

const DialogWrapper = styled.div`
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 1000;
`;

DialogWrapper.defaultProps = {
  className: 'fixed'
};

class Dialog extends React.Component {
  static propTypes = {
    children: React.PropTypes.node,
    closeable: React.PropTypes.bool,
    isOpen: React.PropTypes.bool,
    onRequestClose: React.PropTypes.func,
    width: React.PropTypes.number
  };

  static defaultProps = {
    closeable: true,
    isOpen: false,
    width: 500
  };

  constructor(initialProps) {
    super(initialProps);

    let rendered = false;
    let visible = false;

    if (initialProps.isOpen) {
      rendered = visible = true;
    }

    this.state = {
      rendered,
      visible
    };
  }

  componentDidMount() {
    document.documentElement.addEventListener('keydown', this.handleDocumentKeyDown, false);
  }

  componentWillUnmount() {
    document.documentElement.removeEventListener('keydown', this.handleDocumentKeyDown);
  }

  componentWillReceiveProps(nextProps) {
    // Opening the dialog
    if (!this.props.isOpen && nextProps.isOpen) {
      this.setState({ rendered: true }, () => {
        this.setState({ visible: true });
      });
    }

    // Closing the dialog
    if (this.props.isOpen && !nextProps.isOpen) {
      this.setState({ visible: false }, () => {
        // Give the animation some time to finish, then remove the dialog from
        // the DOM
        setTimeout(() => {
          this.setState({ rendered: false });
        }, 150);
      });
    }
  }

  maybeClose = (event) => {
    event.preventDefault();
    if (typeof this.props.onRequestClose === 'function') {
      this.props.onRequestClose();
    }
  };

  handleCloseClick = (event) => {
    this.maybeClose(event);
  };

  handleDocumentKeyDown = (event) => {
    // Close the dialog on hitting the escape key
    if (this.state.visible && event.keyCode === 27) {
      this.maybeClose(event);
    }
  };

  renderBackdrop() {
    if (!this.state.visible) {
      return;
    }

    return <DialogBackdrop />;
  }

  renderCloseButton() {
    if (!this.props.closeable) {
      return;
    }

    return (
      <CloseButton onClick={this.handleCloseClick}>
        <Icon className="mx-auto" icon="close" title="Close" />
      </CloseButton>
    );
  }

  renderDialog() {
    if (!this.state.visible) {
      return;
    }

    return (
      <DialogContainer>
        <DialogBox width={this.props.width}>
          {this.renderCloseButton()}
          {this.props.children}
        </DialogBox>
      </DialogContainer>
    );
  }

  render() {
    if (!this.state.rendered) {
      return null;
    }

    return (
      <DialogWrapper>
        {this.renderBackdrop()}
        <ReactCSSTransitionGroup transitionName="transition-slide-up" transitionEnterTimeout={150} transitionLeaveTimeout={300}>
          {this.renderDialog()}
        </ReactCSSTransitionGroup>
      </DialogWrapper>
    );
  }
}

export default Dialog;
<|endoftext|>