<commit_before>/*global define, window, WeakMap, console, Proxy */
/*jslint indent: 2, todo: true, nomen: true */

define('blame', [], function () {
  'use strict';

  var blame = Object.create(Object.prototype);

  blame.DEBUG = true;

  function unused() { return; }
  unused(unused);

  function is_object(obj) {
    return !!(obj && (typeof obj === 'object'));
  }

  function is_function(value) {
    return typeof value === 'function';
  }

  function is_number(value) {
    return typeof value === 'number';
  }

  function is_boolean(value) {
    return typeof value === 'boolean';
  }

  function is_string(value) {
    return typeof value === 'string';
  }

  function is_array(value) {
    return Array.isArray(value);
  }

  function is_undefined(value) {
    return value === undefined;
  }

  // Type Definition
  function Type(description, contract) {
    if (!(this instanceof Type)) {
      return new Type(description, contract);
    }

    this.description = String(description);

    if (!is_function(contract)) {
      throw new Error(contract + ' is not a function');
    }

    this.contract = contract;
  }

  Type.prototype.contract = function () {
    throw new Error('Empty test');
  };

  // Define a simple contract
  function simple_contract(test) {
    return function (value, label) {
      if (!test(value)) {
        throw new Error(label);
      }
      return value;
    };
  }

  function typedef(name, contract) {
    blame[name] = new Type(name, contract);
  }

  typedef('Num', simple_contract(is_number));
  typedef('Str', simple_contract(is_string));
  typedef('Bool', simple_contract(is_boolean));
  typedef('Fun', simple_contract(is_function));
  typedef('Undefined', simple_contract(is_undefined));

  // Wrapping
  // ========
  function wrap(type, value, label) {
    // TODO: Consider removing this
    if (!(type instanceof Type)) {
      throw new Error('This is not a type!');
    }
    return type.contract(value, label);
  }
  blame.wrap = wrap;

  // Higher Order Contracts
  // ======================

  // Multiple function composition (Chains the contracts)
  function compose() {
    var contracts = Array.prototype.slice.call(arguments || []);

    if (contracts.length < 2) {
      throw new Error('Incorrect Number of contracts: ' + contracts.length);
    }

    return function () {
      var args = Array.prototype.slice.call(arguments || []),
        length = contracts.length,
        interim;

      while (length--) {
        interim = contracts[length].apply(this, args);
        args[0] = interim;
      }

      return args[0];
    };
  }

  // Mapper over the arrays
  function map(array, f) {
    var i, result;

    // For now work only for arrays
    if (!is_array(array)) {
      throw new TypeError(array + 'is not an array');
    }

    result = [];

    for (i = 0; i < array.length; i++) {
      result[i] = f(array[i], i, array);
    }

    return result;
  }

  // Iterate over keys in an objects
  function each(object, f) {
    var key;

    if (!is_object(object)) {
      throw new TypeError(object + 'is not an object');
    }
    for (key in object) {
      if (object.hasOwnProperty(key)) {
        if(f(key)) {
          break;
        }
      }
    }
  }

  // Type Variable Context
  // ---------------------
  // Seals made within a given context are modeled in the following way:
  // - Tyvars - contains a set of type variables declared in the context
  // - Bindings - contains a map from to tokens to objects which contain:
  //   - the type variable they were sealed with
  //   - the value that was sealed *in* the token
  function Context(old_context) {
    var self = this;
    if (old_context && !(old_context instanceof Context)) {
      throw new TypeError(old_context + ' is not a Context');
    }

    this.tyvars = {};
    this.bindings = new WeakMap();
    this.tokens = [];

    // Inherit from old_context
    if (old_context) {
      each(old_context.tyvars, function (key) {
        self.tyvars[key] = old_context.tyvars[key];
      });

      old_context.tokens.forEach(function (token) {
        var binding = old_context.bindings.get(token);

        self.tokens.push(token);
        self.bindings.set(token, binding);
      });
    }
  }

  // Defining the function type
  // --------------------------
  function TFun() {
    var obj, args, description, domain, range;

    // Parse the arguments
    args = Array.prototype.slice.call(arguments || []);

    if (!(this instanceof TFun)) {
      obj = Object.create(TFun.prototype);
      TFun.apply(obj, args);
      return obj;
    }

    if (args.length < 1) {
      throw new Error('Not enough arguments');
    }

    // Check if all arguments are Type and generate descriptions
    args.forEach(function (arg, index) {
      if (!(arg instanceof Type)) {
        throw new Error('argument ' + index + ' is not a Type');
      }
    });

    description = map(args, function (arg) {
      var new_description = arg.description;
      if (new_description.indexOf(' -> ') !== -1) {
        new_description = '(' + new_description + ')';
      }
      return new_description;
    }).join(' -> ');

    // Domain and range arguments
    domain = args.slice(0, -1);
    range = args[args.length - 1];

    // Proxy Wrapper
    // -------------
    // This contract generates a Proxy wrapper for the functions
    function contract(fun, label, context) {
      var negated, handler;

      negated = '~' + label;

      function wrap_argument(context) {
        return function (arg, index) {
          return domain[index].contract.call(undefined, arg, negated, context);
        };
      }

      handler = {
        apply: function (target, thisArg, args) {
          var wrapped_args, result, my_context;

          if (args.length !== domain.length) {
            throw new Error('Wrong number of arguments: got ' + args.length +
                            ', expected ' + domain.length);
          }

          my_context = new Context(context);
          wrapped_args = map(args, wrap_argument(my_context));
          result = target.apply(thisArg, wrapped_args);

          return range.contract.call(undefined, result, label, my_context, true);
        },
        construct: function (target, args) {
          var wrapped_args, instance, my_context;

          my_context = new Context(context);
          wrapped_args = map(args, wrap_argument(my_context));
          instance = Object.create(target.prototype);

          target.apply(instance, wrapped_args);

          return range.contract.call(undefined, instance, label, context, true);
        }
      };

      return new Proxy(fun, handler);
    }

    this.description = description;
    this.contract = compose(blame.Fun.contract, contract);
  }
  TFun.prototype = Object.create(Type.prototype);

  // TFun is exported as tfun for convenience purposes
  blame.tfun = TFun;

  function Forall(id, type) {
    if (!(this instanceof Forall)) {
      return new Forall(id, type);
    }

    var tyvar = String(id);

    if(!(type instanceof TFun)) {
      throw new TypeError(type + 'is not a TFun or Forall');
    }

    this.description = 'forall ' + id + ', ' + type.description;

    this.contract = function (value, label, context) {
      var my_context = new Context(context);

      if (my_context.tyvars[tyvar]) {
        throw new TypeError('Duplicate type variable: ' + tyvar);
      }

      // Declare a new type variable
      my_context.tyvars[tyvar] = true;

      return type.contract.call(undefined, value, label, my_context);
    };
  }
  Forall.prototype = Object.create(TFun.prototype);

  blame.forall = Forall;

  function Binding(tyvar, value) {
    this.tyvar = tyvar;
    this.value = value;
  }
  Binding.prototype.tyvar = '';
  Binding.prototype.value = null;

  // Token
  // -----
  // Replaces the sealed value
  function Token(tyvar) {
    this.tyvar = tyvar;
  }
  Token.prototype.tyvar = '';

  // Preventing all object like operations on tokens
  function token(tyvar, label) {
    var handler = {}, t = new Token(tyvar);

    function panic() {
      throw new TypeError(label + ', Accessing properties of token ' + token.tyvar);
    }

    if (!blame.DEBUG) {
      [
        'getOwnPropertyDescriptor',
        'getOwnPropertyNames',
        'defineProperty',
        'deleteProperty',
        'freeze',
        'seal',
        'preventExtensions',
        'has',
        'hasOwn',
        'get',
        'set',
        'enumerate',
        'iterate',
        'keys',
        'apply',
        'construct'
      ].forEach(function (e) {
        handler[e] = panic;
      });
    }

    return new Proxy(t, handler);
  }

  function is_unsealed(value) {
    return !(value instanceof Token);
  }

  // Sealing function
  // ----------------
  // Sealing the value inside a token by using the method of storing private
  // properties of an object using a WeakMap.
  //
  // References:
  // * https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Contributor_s_Guide/Private_Properties#Using_WeakMaps
  // * http://fitzgeraldnick.com/weblog/53/
  function seal(value, tyvar, label, context) {
    if (!(context instanceof Context)) {
      throw new TypeError(context + ' is not a Context');
    }

    // TODO: Verify what to throw
    if (!context.tyvars[tyvar]) {
      throw new TypeError(tyvar + ' is not defined,' + label);
    }

    // TODO: Unsure if the label is proper here
    var my_token = token(tyvar, label),
      binding = new Binding(tyvar, value);

    context.bindings.set(my_token, binding);
    context.tokens.push(my_token);

    return my_token;
  }

  // Unsealing function
  // ------------------
  function unseal(token, tyvar, label, context) {
    if (is_unsealed(token)) {
      throw new TypeError (label + ', not a token sealed by ' + tyvar);
    }

    if (!context.bindings.has(token)) {
      throw new TypeError (label + ', token sealed by a different forall');
    }

    var binding = context.bindings.get(token);

    if (binding.tyvar !== tyvar) {
      throw new TypeError (label + ', wrong seal, ' + binding.tyvar + ' instead of ' + tyvar);
    }

    return binding.value;
  }

  function Tyvar(id) {
    if (!(this instanceof Tyvar)) {
      return new Tyvar(id);
    }

    var tyvar = String(id);
    this.description = tyvar;
    this.contract = function(value, label, context, is_unseal) {
      if (is_unseal) {
        // This corresponds to the *:X cast
        return unseal(value, tyvar, label, context);
      }

      // This corresponds to the X:* cast
      return seal(value, tyvar, label, context);
    };
  }
  Tyvar.prototype = Object.create(Type.prototype);

  blame.tyvar = Tyvar;

  // Definition of a simple array
  typedef('Arr', simple_contract(is_array));

  function toUint32(value) {
    return (Number(value) >>> 0);
  }

  var ARRAY_API = {
    // Property
    length: blame.Num,

    // Mutator methods
    fill: false,
    pop: false,
    push: false,
    reverse: false,
    shift: false,
    sort: false,
    splice: false,
    unshift: false,

    // Accessor methods
    concat: false,
    join: false,
    slice: false,
    toString: false,
    toLocaleString: false,
    indexOf: false,
    lastIndexOf: false
  };

  // Array wrapper for blame
  function TArr(type) {
    if (!(this instanceof TArr)) {
      return new TArr(type);
    }

    if (!(type instanceof Type)) {
      throw new TypeError (type + ' is not a type');
    }

    this.description = '[' + type.description + ']';

    function contract(value, label, context, is_unseal) {
      // TODO: Verify if unseal makes any difference for now
      unused(is_unseal);

      var handler = {
        // Getter
        get: function (target, name, receiver) {
          var index;
          unused(receiver);

          // Is it an index, as defined by ECMA 5, $15.4,
          // http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

          // Calculating ToString(ToUint32(name))
          // Hack to convert to ToUint32
          // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Polyfill
          index = toUint32(name);

          if (name === index.toString() && index !== (-1 >>> 0)) {
            return type.contract(target[name], label, context);
          }

          if (ARRAY_API.hasOwnProperty(name)) {
            if (ARRAY_API[name]) {
              return ARRAY_API[name].contract(target[name], label, context);
            }

            throw new Error('Array API method ' + name + ' not yet implemented');
          }

          throw new TypeError('~' + label + ', wrong property ' + name + ' of an array');
        },
        // Setter
        set: function (target, name, value, receiver) {
          var index, negated;
          unused(receiver);

          index = toUint32(name);

          if (name === index.toString() && index !== (-1 >>> 0)) {
            // If Object is sealed do nothing
            if (Object.isFrozen(target)) {
              return false;
            }

            if (Object.isSealed(target) && (index >= target.length)) {
              return false;
            }
            negated = '~' + label;

            target[name] = type.contract(value, negated, context, true);
          }
        }

      };
      return new Proxy(value, handler);
    }

    this.contract = compose(blame.Arr.contract, contract);
  }

  TArr.prototype = Object.create(Type.prototype);

  blame.tarr = TArr;

  return blame;
});

// vim: set ts=2 sw=2 sts=2 et :
<commit_msg>Fix the implementation of unsealing arrays<commit_after>/*global define, window, WeakMap, console, Proxy */
/*jslint indent: 2, todo: true, nomen: true */

define('blame', [], function () {
  'use strict';

  var blame = Object.create(Object.prototype);

  blame.DEBUG = true;

  function unused() { return; }
  unused(unused);

  function is_object(obj) {
    return !!(obj && (typeof obj === 'object'));
  }

  function is_function(value) {
    return typeof value === 'function';
  }

  function is_number(value) {
    return typeof value === 'number';
  }

  function is_boolean(value) {
    return typeof value === 'boolean';
  }

  function is_string(value) {
    return typeof value === 'string';
  }

  function is_array(value) {
    return Array.isArray(value);
  }

  function is_undefined(value) {
    return value === undefined;
  }

  // Type Definition
  function Type(description, contract) {
    if (!(this instanceof Type)) {
      return new Type(description, contract);
    }

    this.description = String(description);

    if (!is_function(contract)) {
      throw new Error(contract + ' is not a function');
    }

    this.contract = contract;
  }

  Type.prototype.contract = function () {
    throw new Error('Empty test');
  };

  // Define a simple contract
  function simple_contract(test) {
    return function (value, label) {
      if (!test(value)) {
        throw new Error(label);
      }
      return value;
    };
  }

  function typedef(name, contract) {
    blame[name] = new Type(name, contract);
  }

  typedef('Num', simple_contract(is_number));
  typedef('Str', simple_contract(is_string));
  typedef('Bool', simple_contract(is_boolean));
  typedef('Fun', simple_contract(is_function));
  typedef('Undefined', simple_contract(is_undefined));

  // Wrapping
  // ========
  function wrap(type, value, label) {
    // TODO: Consider removing this
    if (!(type instanceof Type)) {
      throw new Error('This is not a type!');
    }
    return type.contract(value, label);
  }
  blame.wrap = wrap;

  // Higher Order Contracts
  // ======================

  // Multiple function composition (Chains the contracts)
  function compose() {
    var contracts = Array.prototype.slice.call(arguments || []);

    if (contracts.length < 2) {
      throw new Error('Incorrect Number of contracts: ' + contracts.length);
    }

    return function () {
      var args = Array.prototype.slice.call(arguments || []),
        length = contracts.length,
        interim;

      while (length--) {
        interim = contracts[length].apply(this, args);
        args[0] = interim;
      }

      return args[0];
    };
  }

  // Mapper over the arrays
  function map(array, f) {
    var i, result;

    // For now work only for arrays
    if (!is_array(array)) {
      throw new TypeError(array + 'is not an array');
    }

    result = [];

    for (i = 0; i < array.length; i++) {
      result[i] = f(array[i], i, array);
    }

    return result;
  }

  // Iterate over keys in an objects
  function each(object, f) {
    var key;

    if (!is_object(object)) {
      throw new TypeError(object + 'is not an object');
    }
    for (key in object) {
      if (object.hasOwnProperty(key)) {
        if(f(key)) {
          break;
        }
      }
    }
  }

  // Type Variable Context
  // ---------------------
  // Seals made within a given context are modeled in the following way:
  // - Tyvars - contains a set of type variables declared in the context
  // - Bindings - contains a map from to tokens to objects which contain:
  //   - the type variable they were sealed with
  //   - the value that was sealed *in* the token
  function Context(old_context) {
    var self = this;
    if (old_context && !(old_context instanceof Context)) {
      throw new TypeError(old_context + ' is not a Context');
    }

    this.tyvars = {};
    this.bindings = new WeakMap();
    this.tokens = [];

    // Inherit from old_context
    if (old_context) {
      each(old_context.tyvars, function (key) {
        self.tyvars[key] = old_context.tyvars[key];
      });

      old_context.tokens.forEach(function (token) {
        var binding = old_context.bindings.get(token);

        self.tokens.push(token);
        self.bindings.set(token, binding);
      });
    }
  }

  // Defining the function type
  // --------------------------
  function TFun() {
    var obj, args, description, domain, range;

    // Parse the arguments
    args = Array.prototype.slice.call(arguments || []);

    if (!(this instanceof TFun)) {
      obj = Object.create(TFun.prototype);
      TFun.apply(obj, args);
      return obj;
    }

    if (args.length < 1) {
      throw new Error('Not enough arguments');
    }

    // Check if all arguments are Type and generate descriptions
    args.forEach(function (arg, index) {
      if (!(arg instanceof Type)) {
        throw new Error('argument ' + index + ' is not a Type');
      }
    });

    description = map(args, function (arg) {
      var new_description = arg.description;
      if (new_description.indexOf(' -> ') !== -1) {
        new_description = '(' + new_description + ')';
      }
      return new_description;
    }).join(' -> ');

    // Domain and range arguments
    domain = args.slice(0, -1);
    range = args[args.length - 1];

    // Proxy Wrapper
    // -------------
    // This contract generates a Proxy wrapper for the functions
    function contract(fun, label, context) {
      var negated, handler;

      negated = '~' + label;

      function wrap_argument(context) {
        return function (arg, index) {
          return domain[index].contract.call(undefined, arg, negated, context);
        };
      }

      handler = {
        apply: function (target, thisArg, args) {
          var wrapped_args, result, my_context;

          if (args.length !== domain.length) {
            throw new Error('Wrong number of arguments: got ' + args.length +
                            ', expected ' + domain.length);
          }

          my_context = new Context(context);
          wrapped_args = map(args, wrap_argument(my_context));
          result = target.apply(thisArg, wrapped_args);

          return range.contract.call(undefined, result, label, my_context, true);
        },
        construct: function (target, args) {
          var wrapped_args, instance, my_context;

          my_context = new Context(context);
          wrapped_args = map(args, wrap_argument(my_context));
          instance = Object.create(target.prototype);

          target.apply(instance, wrapped_args);

          return range.contract.call(undefined, instance, label, context, true);
        }
      };

      return new Proxy(fun, handler);
    }

    this.description = description;
    this.contract = compose(blame.Fun.contract, contract);
  }
  TFun.prototype = Object.create(Type.prototype);

  // TFun is exported as tfun for convenience purposes
  blame.tfun = TFun;

  function Forall(id, type) {
    if (!(this instanceof Forall)) {
      return new Forall(id, type);
    }

    var tyvar = String(id);

    if(!(type instanceof TFun)) {
      throw new TypeError(type + 'is not a TFun or Forall');
    }

    this.description = 'forall ' + id + ', ' + type.description;

    this.contract = function (value, label, context) {
      var my_context = new Context(context);

      if (my_context.tyvars[tyvar]) {
        throw new TypeError('Duplicate type variable: ' + tyvar);
      }

      // Declare a new type variable
      my_context.tyvars[tyvar] = true;

      return type.contract.call(undefined, value, label, my_context);
    };
  }
  Forall.prototype = Object.create(TFun.prototype);

  blame.forall = Forall;

  function Binding(tyvar, value) {
    this.tyvar = tyvar;
    this.value = value;
  }
  Binding.prototype.tyvar = '';
  Binding.prototype.value = null;

  // Token
  // -----
  // Replaces the sealed value
  function Token(tyvar) {
    this.tyvar = tyvar;
  }
  Token.prototype.tyvar = '';

  // Preventing all object like operations on tokens
  function token(tyvar, label) {
    var handler = {}, t = new Token(tyvar);

    function panic() {
      throw new TypeError(label + ', Accessing properties of token ' + token.tyvar);
    }

    if (!blame.DEBUG) {
      [
        'getOwnPropertyDescriptor',
        'getOwnPropertyNames',
        'defineProperty',
        'deleteProperty',
        'freeze',
        'seal',
        'preventExtensions',
        'has',
        'hasOwn',
        'get',
        'set',
        'enumerate',
        'iterate',
        'keys',
        'apply',
        'construct'
      ].forEach(function (e) {
        handler[e] = panic;
      });
    }

    return new Proxy(t, handler);
  }

  function is_unsealed(value) {
    return !(value instanceof Token);
  }

  // Sealing function
  // ----------------
  // Sealing the value inside a token by using the method of storing private
  // properties of an object using a WeakMap.
  //
  // References:
  // * https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Contributor_s_Guide/Private_Properties#Using_WeakMaps
  // * http://fitzgeraldnick.com/weblog/53/
  function seal(value, tyvar, label, context) {
    if (!(context instanceof Context)) {
      throw new TypeError(context + ' is not a Context');
    }

    // TODO: Verify what to throw
    if (!context.tyvars[tyvar]) {
      throw new TypeError(tyvar + ' is not defined,' + label);
    }

    // TODO: Unsure if the label is proper here
    var my_token = token(tyvar, label),
      binding = new Binding(tyvar, value);

    context.bindings.set(my_token, binding);
    context.tokens.push(my_token);

    return my_token;
  }

  // Unsealing function
  // ------------------
  function unseal(token, tyvar, label, context) {
    if (is_unsealed(token)) {
      throw new TypeError (label + ', not a token sealed by ' + tyvar);
    }

    if (!context.bindings.has(token)) {
      throw new TypeError (label + ', token sealed by a different forall');
    }

    var binding = context.bindings.get(token);

    if (binding.tyvar !== tyvar) {
      throw new TypeError (label + ', wrong seal, ' + binding.tyvar + ' instead of ' + tyvar);
    }

    return binding.value;
  }

  function Tyvar(id) {
    if (!(this instanceof Tyvar)) {
      return new Tyvar(id);
    }

    var tyvar = String(id);
    this.description = tyvar;
    this.contract = function(value, label, context, is_unseal) {
      if (is_unseal) {
        // This corresponds to the *:X cast
        return unseal(value, tyvar, label, context);
      }

      // This corresponds to the X:* cast
      return seal(value, tyvar, label, context);
    };
  }
  Tyvar.prototype = Object.create(Type.prototype);

  blame.tyvar = Tyvar;

  // Definition of a simple array
  typedef('Arr', simple_contract(is_array));

  function toUint32(value) {
    return (Number(value) >>> 0);
  }

  var ARRAY_API = {
    // Property
    length: blame.Num,

    // Mutator methods
    fill: false,
    pop: false,
    push: false,
    reverse: false,
    shift: false,
    sort: false,
    splice: false,
    unshift: false,

    // Accessor methods
    concat: false,
    join: false,
    slice: false,
    toString: false,
    toLocaleString: false,
    indexOf: false,
    lastIndexOf: false
  };

  // Array wrapper for blame
  function TArr(type) {
    if (!(this instanceof TArr)) {
      return new TArr(type);
    }

    if (!(type instanceof Type)) {
      throw new TypeError (type + ' is not a type');
    }

    this.description = '[' + type.description + ']';

    function contract(value, label, context, is_unseal) {
      // TODO: Verify if unseal makes any difference for now

      var handler = {
        // Getter
        get: function (target, name, receiver) {
          var index;
          unused(receiver);

          // Is it an index, as defined by ECMA 5, $15.4,
          // http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

          // Calculating ToString(ToUint32(name))
          // Hack to convert to ToUint32
          // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Polyfill
          index = toUint32(name);

          if (name === index.toString() && index !== (-1 >>> 0)) {
            return type.contract(target[name], label, context);
          }

          if (ARRAY_API.hasOwnProperty(name)) {
            if (ARRAY_API[name]) {
              return ARRAY_API[name].contract(target[name], label, context, is_unseal);
            }

            throw new Error('Array API method ' + name + ' not yet implemented');
          }

          throw new TypeError('~' + label + ', wrong property ' + name + ' of an array');
        },
        // Setter
        set: function (target, name, value, receiver) {
          var index, negated;
          unused(receiver);

          index = toUint32(name);

          if (name === index.toString() && index !== (-1 >>> 0)) {
            // If Object is sealed do nothing
            if (Object.isFrozen(target)) {
              return false;
            }

            if (Object.isSealed(target) && (index >= target.length)) {
              return false;
            }
            negated = '~' + label;

            target[name] = type.contract(value, negated, context, !(is_unseal || false));
          }
        }

      };
      return new Proxy(value, handler);
    }

    this.contract = compose(blame.Arr.contract, contract);
  }

  TArr.prototype = Object.create(Type.prototype);

  blame.tarr = TArr;

  return blame;
});

// vim: set ts=2 sw=2 sts=2 et :
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var parseString = require('xml2js').parseString;

var blast = {
  stringOutput: false,
  customBlastLocation: null
};

lookupCustomBlastLocation();

function lookupCustomBlastLocation() {
  var lookDir = path.join(__dirname, '../bin');
  var binStats;
  var binFiles;
  var pathToFirst;
  var innerBin;
  var innerBinStats;

  try {
    binStats = fs.lstatSync(lookDir);
    if(binStats.isDirectory()) {
      binFiles = fs.readdirSync(lookDir);
      if(binFiles.length){
        pathToFirst = path.join(lookDir, binFiles[0]);
        innerBin = path.join(pathToFirst, 'bin');
        innerBinStats = fs.lstatSync(innerBin);
        if(innerBinStats.isDirectory()) {
          blast.customBlastLocation = innerBin;
        }
      }
    }
  } catch(e){}

}

blast.outputString = function (bool) {

  blast.stringOutput = !!(!bool || bool == true);
};

blast.blastN = function (db, query, cb) {
  blaster('blastn', db, query, cb);
};

blast.blastP = function (db, query, cb) {
  blaster('blastp', db, query, cb);
};

blast.blastX = function (db, query, cb) {
  blaster('blastx', db, query, cb);
};

blast.tblastN = function (db, query, cb) {
  blaster('tblastn', db, query, cb);
};

blast.tblastX = function (db, query, cb) {
  blaster('tblastx', db, query, cb);
};

function generateGuid() {
  var result, i, j;
  result = '';
  for (j = 0; j < 32; j++) {
    if (j === 8 || j === 12 || j === 16 || j === 20)
      result = result + '-';
    i = Math.floor(Math.random() * 16).toString(16).toUpperCase();
    result = result + i;
  }
  return result;
}
function postBlast(err, stdOut, stdError, outFile, cb) {

  if (err) {
    console.log('blast error', stdError);
    return cb(err, null);
  } else {
    fs.readFile(outFile, 'utf8', function (err, data) {
      if (!blast.stringOutput) {
        parseString(data, function (err, result) {
          return cb(err, result);
        });
      } else {
        return cb(err, data);
      }
    });
  }
}

function blaster(type, db, query, cb) {

  var pathW = '/tmp/' + Date.now() + '.fasta';
  fs.writeFileSync(pathW, query);

  var outPath = '/tmp/';
  var outFile = outPath + generateGuid() + '.out';
  var blastCommand = type + ' -query ' + pathW + ' -out ' + outFile + ' -db ' + db;

  if (!blast.stringOutput) {
    blastCommand += ' -outfmt 5';
  }

  run(blastCommand, function (err, stdOut, stdError) {
    postBlast(err, stdOut, stdError, outFile, cb);
  });
}

function run(toRun, cb) {
  var exec = require('child_process').exec;

  if (blast.customBlastLocation != null) {
    toRun = blast.customBlastLocation + '/' + toRun
  }
  console.log('RUNNING', toRun);
  exec(toRun, cb);
}

blast.makeDB = function (type, fileIn, outPath, name, cb) {

  if (!type) {
    return cb(new Error('no type supplied'));
  }
  if (!fileIn) {
    return cb(new Error('no file supplied'));
  }
  if (!outPath) {
    return cb(new Error('no output path supplied'));
  }

  var fileNamePartOne = fileIn.replace(/^.*[\\\/]/, '');// remove directories from path
  var filename = fileNamePartOne.substr(0, fileNamePartOne.lastIndexOf('.')); //remove file extensions

  if (outPath.slice(-1) !== '/') {
    outPath = outPath + '/'; // add / out path is one is not supplied
  }

  var fileOut = outPath + filename;

  var makeCommand = 'makeblastdb -in ' + fileIn + ' -dbtype ' + type + ' -out ' + fileOut + ' -title ' + name;
  run(makeCommand, function (err, stdOut, stdErr) {
    return cb(err, stdOut, stdErr, fileOut);
  });

};

module.exports = blast;
<commit_msg>Added blast function to handle additional options.<commit_after>var fs = require('fs');
var path = require('path');
var exec = require('child_process').exec;
var _ = require('lodash');
var uuid = require('uuid');
var parseString = require('xml2js').parseString;

var blast = {
  stringOutput: false,
  customBlastLocation: null
};

_.attempt(lookupCustomBlastLocation);

function lookupCustomBlastLocation() {
  var lookDir = path.join(__dirname, '../bin');
  var binStats;
  var binFiles;
  var pathToFirst;
  var innerBin;
  var innerBinStats;

  binStats = fs.lstatSync(lookDir);
  if (binStats.isDirectory()) {
    binFiles = fs.readdirSync(lookDir);
    if (binFiles.length) {
      pathToFirst = path.join(lookDir, binFiles[0]);
      innerBin = path.join(pathToFirst, 'bin');
      innerBinStats = fs.lstatSync(innerBin);
      if (innerBinStats.isDirectory()) {
        blast.customBlastLocation = innerBin;
      }
    }
  }

}

blast.outputString = function(bool) {
  blast.stringOutput = !!(!bool || bool == true);
};

blast.blastN = function(db, query, cb) {
  blaster('blastn', db, query, cb);
};

blast.blastP = function(db, query, cb) {
  blaster('blastp', db, query, cb);
};

blast.blastX = function(db, query, cb) {
  blaster('blastx', db, query, cb);
};

blast.tblastN = function(db, query, cb) {
  blaster('tblastn', db, query, cb);
};

blast.tblastX = function(db, query, cb) {
  blaster('tblastx', db, query, cb);
};

blast.blast = function(options, cb) {
  var nonBlastOptions = ['type', 'outputDirectory', 'rawOutput'];
  var optArr = [];
  var guid = uuid.v1();
  var queryString;
  var opts = {
    type: 'blastn',
    outputDirectory: '/tmp',
    rawOutput: false,
    db: 'nt',
    outfmt: 5
  };

  _.extend(opts, options);

  queryString = opts.query;

  if (!queryString) {
    return cb(new Error('Query must be supplied.'));
  }

  opts.query = path.join(opts.outputDirectory, guid + '.fasta');
  opts.out = path.join(opts.outputDirectory, guid + '.out');

  if(opts.remote) {
    opts.remote = '';
  }

  _.each(opts, function(value, key) {
    if(nonBlastOptions.indexOf(key) > -1){
      return;
    }

    optArr.push('-' + key);
    optArr.push(value);
  });

  fs.writeFile(opts.query, queryString, function(err) {
    if (err) {
      return cb(err);
    }

    run(opts.type + ' ' + optArr.join(' '), function(err, stdOut, stdError) {
      postBlast(err, stdOut, stdError, opts, cb);
    });

  });

};

function postBlast(err, stdOut, stdError, options, cb) {
  var outFile = options.out;
  var isRaw = options.rawOutput || blast.stringOutput || !options.outfmt.toString().match(/^(.)?5/);

  if (err) {
    return cb(err);
  }

  fs.readFile(outFile, 'utf8', function(err, data) {
    if(isRaw){
      return cb(null, data);
    }

    parseString(data, function(err, result) {
      return cb(null, result);
    });
  });
}

function blaster(type, db, query, cb) {
  var pathW = '/tmp/' + Date.now() + '.fasta';
  fs.writeFileSync(pathW, query);

  var outPath = '/tmp/';
  var outFile = outPath + uuid.v1() + '.out';
  var blastCommand = type + ' -query ' + pathW + ' -out ' + outFile + ' -db ' + db;

  if (!blast.stringOutput) {
    blastCommand += ' -outfmt 5';
  }

  run(blastCommand, function(err, stdOut, stdError) {
    postBlast(err, stdOut, stdError, {out: outFile, outfmt: 5}, false, cb);
  });
}

function run(toRun, cb) {
  if (blast.customBlastLocation) {
    toRun = path.join(blast.customBlastLocation, toRun);
  }

  console.log('Blasting: ', toRun);
  exec(toRun, cb);
}

blast.makeDB = function(type, fileIn, outPath, name, cb) {

  if (!type) {
    return cb(new Error('no type supplied'));
  }
  if (!fileIn) {
    return cb(new Error('no file supplied'));
  }
  if (!outPath) {
    return cb(new Error('no output path supplied'));
  }

  var fileNamePartOne = fileIn.replace(/^.*[\\\/]/, '');// remove directories from path
  var filename = fileNamePartOne.substr(0, fileNamePartOne.lastIndexOf('.')); //remove file extensions

  if (outPath.slice(-1) !== '/') {
    outPath = outPath + '/'; // add / out path is one is not supplied
  }

  var fileOut = outPath + filename;

  var makeCommand = 'makeblastdb -in ' + fileIn + ' -dbtype ' + type + ' -out ' + fileOut + ' -title ' + name;
  run(makeCommand, function(err, stdOut, stdErr) {
    return cb(err, stdOut, stdErr, fileOut);
  });

};

module.exports = blast;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var util = require('util');
var bs2 = require('bs2-programmer');
var bluebird = require('bluebird');
var Bs2Programmer = bs2.Programmer;
var reemit = require('re-emitter');
var bs2tokenizer = require('pbasic-tokenizer');
var EventEmitter = require('events').EventEmitter;
var Bs2SerialProtocol = require('bs2-serial-protocol');

function internalCompile(source){
  var TModuleRec = bs2tokenizer.compile(source, false);

  var program = {
    data: TModuleRec.PacketBuffer.slice(0, TModuleRec.PacketCount * 18),
    name: TModuleRec.TargetModuleName,
    error: !TModuleRec.Succeeded ? TModuleRec.Error : null
  };

  return program;
}

function Board(options){
  if(!options){
    throw new Error('Options error: no options');
  }

  if(!options.path){
    throw new Error('Options error: no path');
  }

  EventEmitter.call(this);

  this._revision = options.revision || 'bs2';
  this._protocol = new Bs2SerialProtocol(options);
  this._programmer = new Bs2Programmer({
    protocol: this._protocol,
    revision: this._revision
  });

  reemit(this._programmer, this, ['bootloadProgress']);
  reemit(this._protocol, this, ['terminal', 'open', 'close']);
}

util.inherits(Board, EventEmitter);

Board.search = function(portList, options, cb){
  var revisions = _.keys(bs2.revisions);
  return bluebird.reduce(portList, function(boardList, path){

    var protocol = new Bs2SerialProtocol({ path: path });
    return bluebird.reduce(revisions, function(current, rev){
      if(current){
        return current;
      }

      var boardOpts = {
        protocol: protocol,
        revision: rev
      };

      return bs2.identify(boardOpts)
        .then(function(result){
          return _.assign({ path: path, revision: rev }, result);
        })
        .otherwise(function(){
          return null;
        });

    }, null)
    .then(function(board){
      if(board != null){
        var details = {
          name: board.name,
          path: board.path,
          version: board.version,
          board: _.cloneDeep(board),
          match: false,
          program: null
        };
        if(options.source){
          details.program = internalCompile(options.source);
          details.match = details.program.name === board.name;
        }
        boardList.push(details);
      }
      return boardList;
    });

  }, []).nodeify(cb);
};

Board.prototype.bootload = function(program, cb){
  if(program && program.error){
    return bluebird.reject(program.error).nodeify(cb);
  }
  if(!program || !program.data){
    return bluebird.reject(new Error('Options error: no program data')).nodeify(cb);
  }

  return this._programmer.bootload(program.data, cb);
};

Board.compile = function(source){
  return internalCompile(source);
};

Board.prototype.isOpen = function(){
  return !!_.get(this, '_protocol._isOpen');
};

Board.prototype.write = function(data, cb){
  if(typeof data === 'number'){
    data = new Buffer([data]);
  }else if(Array.isArray(data)){
    data = new Buffer(data);
  }
  return this._protocol.write(data, cb);
};

Board.prototype.open = function(cb){
  return this._protocol.open(cb);
};

Board.prototype.close = function(cb){
  return this._protocol.close(cb);
};

Board.getRevisions = function(){
  return bs2.revisions;
};

module.exports = Board;
<commit_msg>Fix progress events<commit_after>'use strict';

var _ = require('lodash');
var util = require('util');
var bs2 = require('bs2-programmer');
var bluebird = require('bluebird');
var Bs2Programmer = bs2.Programmer;
var reemit = require('re-emitter');
var bs2tokenizer = require('pbasic-tokenizer');
var EventEmitter = require('events').EventEmitter;
var Bs2SerialProtocol = require('bs2-serial-protocol');

function internalCompile(source){
  var TModuleRec = bs2tokenizer.compile(source, false);

  var program = {
    data: TModuleRec.PacketBuffer.slice(0, TModuleRec.PacketCount * 18),
    name: TModuleRec.TargetModuleName,
    error: !TModuleRec.Succeeded ? TModuleRec.Error : null
  };

  return program;
}

function Board(options){
  if(!options){
    throw new Error('Options error: no options');
  }

  if(!options.path){
    throw new Error('Options error: no path');
  }

  EventEmitter.call(this);

  this._revision = options.revision || 'bs2';
  this._protocol = new Bs2SerialProtocol(options);
  this._programmer = new Bs2Programmer({
    protocol: this._protocol,
    revision: this._revision
  });

  reemit(this._protocol, this, ['terminal', 'open', 'close']);

  var self = this;
  this._programmer.on('bootloadProgress', function(progress){
    self.emit('progress', progress);
  });
}

util.inherits(Board, EventEmitter);

Board.search = function(portList, options, cb){
  var revisions = _.keys(bs2.revisions);
  return bluebird.reduce(portList, function(boardList, path){

    var protocol = new Bs2SerialProtocol({ path: path });
    return bluebird.reduce(revisions, function(current, rev){
      if(current){
        return current;
      }

      var boardOpts = {
        protocol: protocol,
        revision: rev
      };

      return bs2.identify(boardOpts)
        .then(function(result){
          return _.assign({ path: path, revision: rev }, result);
        })
        .otherwise(function(){
          return null;
        });

    }, null)
    .then(function(board){
      if(board != null){
        var details = {
          name: board.name,
          path: board.path,
          version: board.version,
          board: _.cloneDeep(board),
          match: false,
          program: null
        };
        if(options.source){
          details.program = internalCompile(options.source);
          details.match = details.program.name === board.name;
        }
        boardList.push(details);
      }
      return boardList;
    });

  }, []).nodeify(cb);
};

Board.prototype.bootload = function(program, cb){
  if(program && program.error){
    return bluebird.reject(program.error).nodeify(cb);
  }
  if(!program || !program.data){
    return bluebird.reject(new Error('Options error: no program data')).nodeify(cb);
  }

  return this._programmer.bootload(program.data, cb);
};

Board.compile = function(source){
  return internalCompile(source);
};

Board.prototype.isOpen = function(){
  return !!_.get(this, '_protocol._isOpen');
};

Board.prototype.write = function(data, cb){
  if(typeof data === 'number'){
    data = new Buffer([data]);
  }else if(Array.isArray(data)){
    data = new Buffer(data);
  }
  return this._protocol.write(data, cb);
};

Board.prototype.open = function(cb){
  return this._protocol.open(cb);
};

Board.prototype.close = function(cb){
  return this._protocol.close(cb);
};

Board.getRevisions = function(){
  return bs2.revisions;
};

module.exports = Board;
<|endoftext|>


<commit_before>'use strict';

const { spawn } = require('child_process');
const buildFactory = require('./build');
const callable = require('./utils/callable');
const chalk = require('chalk');
const cnsl = require('./utils/cnsl');
const compact = require('lodash/compact');
const configFactory = require('./config');
const flatten = require('lodash/flatten');
const path = require('path');
const series = require('async/series');

const { BELL, debug, error, print, start, stop, strong } = cnsl;
let serverfarm = null;

/**
 * Buddy instance factory
 * @param {String|Object} configpath [file name | JSON Object]
 * @param {Object} options
 * @returns {Buddy}
 */
module.exports = function buddyFactory (configpath, options) {
  return new Buddy(configpath, options);
};

class Buddy {
  /**
   * Constructor
   * Initialize based on configuration located at 'configpath'
   * The directory tree will be walked if no 'configpath' specified
   * @param {String|Object} configpath [file name | JSON Object]
   * @param {Object} runtimeOptions
   */
  constructor (configpath, runtimeOptions = {}) {
    // Set console behaviour
    cnsl.verbose = runtimeOptions.debug;

    this.building = false;
    this.config = configFactory(configpath, runtimeOptions);
    this.onFileCacheChange = this.onFileCacheChange.bind(this);

    // Initialize builds
    this.builds = this.initBuilds(this.config.build, runtimeOptions);
  }

  /**
   * Build sources based on build targets specified in config
   * @param {Function} fn
   */
  build (fn) {
    start('build');

    // Build targets
    this.run(this.builds, (err, filepaths) => {
      if (err) return fn ? fn(err) : error(err, 2);
      print(`done building in ${chalk.cyan((stop('build') / 1000) + 's')}`, 1);
      // Run script
      this.executeScript();
      if (fn) fn(null, filepaths);
    });
  }

  /**
   * Build sources and watch for changes
   * @param {Function} fn
   */
  watch (fn) {
    // Build first
    this.build((err, filepaths) => {
      if (err) return fn ? fn(err) : error(err, 2);

      if (this.config.runtimeOptions.reload || this.config.runtimeOptions.serve) {
        serverfarm = require('./utils/serverfarm');
        // Start servers
        serverfarm.start(this.config.runtimeOptions.serve, this.config.runtimeOptions.reload, this.config.server, (serverError) => {
          if (serverError) { /* Ignore and keep watching */ }
        });
      } else {
        print('watching files for changes:', 1);
      }
    });
  }

  /**
   * Cleanup after unhandled exception
   */
  exceptionalCleanup () {
    if (serverfarm) serverfarm.stop();
  }

  /**
   * Reset
   */
  destroy () {
    this.exceptionalCleanup();
    this.config.destroy();

    this.config = null;
    this.builds = [];
  }

  /**
   * Recursively initialize all valid build instances
   * @param {Array} builds
   * @param {Object} runtimeOptions
   * @returns {Array}
   */
  initBuilds (builds, runtimeOptions) {
    const init = (builds, isChild) => {
      return builds.map((build) => {
        const instance = buildFactory(build);

        // Setup watch
        if (!isChild && runtimeOptions.watch) {
          build.fileCache.on('change', this.onFileCacheChange);
          // TODO: add error listener
        }

        // Traverse
        if (instance.hasChildren) instance.build = init(instance.build, true);
        return instance;
      });
    };

    return init(builds);
  }

  /**
   * Run all build targets
   * @param {Array} builds
   * @param {Function} fn(err, filepaths)
   */
  run (builds, fn) {
    this.building = true;

    // Execute builds in sequence
    series(builds.map((build) => callable(build, 'run')),
      (err, results) => {
        if (err) return fn(err);

        this.building = false;
        fn(null, compact(flatten(results)).map((result) => result.filepath));
      }
    );
  }

  /**
   * Run the script defined in config 'script'
   */
  executeScript () {
    let hasErrored = false;
    let args, command, script;

    if (this.config.runtimeOptions.script && (script = this.config.script)) {
      script = script.split(' ');
      command = script.shift();
      args = script;

      print('executing script...', 1);
      debug(`execute: ${strong(this.config.script)}`, 3);

      script = spawn(command, args, { cwd: process.cwd() });

      script.stdout.on('data', (data) => {
        process.stdout.write(data.toString());
      });

      script.stderr.on('data', (data) => {
        process.stderr.write(data.toString());
        hasErrored = true;
      });

      script.on('close', (code) => {
        if (hasErrored) process.stderr.write(BELL);
      });
    }
  }

  /**
   * Handle cache changes
   * @param {File} file
   */
  onFileCacheChange (file) {
    const now = new Date();
    const builds = this.builds.filter((build) => build.hasFile(file));
    // Determine if any changes to app server code that needs a restart
    const servers = builds.filter((build) => build.isAppServer);

    if (!this.building) {
      print(`[${now.toLocaleTimeString()}] ${chalk.yellow('changed')} ${strong(path.relative(process.cwd(), file.filepath))}`, 1);

      start('watch');

      this.run(builds, (err, filepaths) => {
        // Don't throw
        if (err) return error(err, 2, false);
        if (serverfarm) {
          // Trigger partial refresh if only 1 css file, full reload if not
          const filepath = (filepaths.length == 1 && path.extname(filepaths[0]) == '.css')
            ? filepaths[0]
            : 'foo.js';

          // Refresh browser
          if (!servers.length) {
            serverfarm.refresh(path.basename(filepath));
          } else {
            // Restart app server
            serverfarm.restart((err) => {
              if (err) { /* ignore */ }
              // Refresh browser
              serverfarm.refresh(path.basename(filepath));
            });
          }
        }
        print(`done re-building in ${chalk.cyan((stop('watch') / 1000) + 's')}`, 1);
        // Run test script
        this.executeScript();
      });
    }
  }
}<commit_msg>adjust log messages<commit_after>'use strict';

const { spawn } = require('child_process');
const buildFactory = require('./build');
const callable = require('./utils/callable');
const chalk = require('chalk');
const cnsl = require('./utils/cnsl');
const compact = require('lodash/compact');
const configFactory = require('./config');
const flatten = require('lodash/flatten');
const path = require('path');
const series = require('async/series');

const { BELL, debug, error, print, start, stop, strong } = cnsl;
let serverfarm = null;

/**
 * Buddy instance factory
 * @param {String|Object} configpath [file name | JSON Object]
 * @param {Object} options
 * @returns {Buddy}
 */
module.exports = function buddyFactory (configpath, options) {
  return new Buddy(configpath, options);
};

class Buddy {
  /**
   * Constructor
   * Initialize based on configuration located at 'configpath'
   * The directory tree will be walked if no 'configpath' specified
   * @param {String|Object} configpath [file name | JSON Object]
   * @param {Object} runtimeOptions
   */
  constructor (configpath, runtimeOptions = {}) {
    // Set console behaviour
    cnsl.verbose = runtimeOptions.debug;

    this.building = false;
    this.config = configFactory(configpath, runtimeOptions);
    this.onFileCacheChange = this.onFileCacheChange.bind(this);

    // Initialize builds
    this.builds = this.initBuilds(this.config.build, runtimeOptions);
  }

  /**
   * Build sources based on build targets specified in config
   * @param {Function} fn
   */
  build (fn) {
    start('build');

    // Build targets
    this.run(this.builds, (err, filepaths) => {
      if (err) return fn ? fn(err) : error(err, 2);
      print(`done in ${chalk.cyan((stop('build') / 1000) + 's')}`, 0);
      // Run script
      this.executeScript();
      if (fn) fn(null, filepaths);
    });
  }

  /**
   * Build sources and watch for changes
   * @param {Function} fn
   */
  watch (fn) {
    // Build first
    this.build((err, filepaths) => {
      if (err) return fn ? fn(err) : error(err, 2);

      if (this.config.runtimeOptions.reload || this.config.runtimeOptions.serve) {
        serverfarm = require('./utils/serverfarm');
        // Start servers
        serverfarm.start(this.config.runtimeOptions.serve, this.config.runtimeOptions.reload, this.config.server, (serverError) => {
          if (serverError) { /* Ignore and keep watching */ }
        });
      } else {
        print('watching files for changes:', 1);
      }
    });
  }

  /**
   * Cleanup after unhandled exception
   */
  exceptionalCleanup () {
    if (serverfarm) serverfarm.stop();
  }

  /**
   * Reset
   */
  destroy () {
    this.exceptionalCleanup();
    this.config.destroy();

    this.config = null;
    this.builds = [];
  }

  /**
   * Recursively initialize all valid build instances
   * @param {Array} builds
   * @param {Object} runtimeOptions
   * @returns {Array}
   */
  initBuilds (builds, runtimeOptions) {
    const init = (builds, isChild) => {
      return builds.map((build) => {
        const instance = buildFactory(build);

        // Setup watch
        if (!isChild && runtimeOptions.watch) {
          build.fileCache.on('change', this.onFileCacheChange);
          // TODO: add error listener
        }

        // Traverse
        if (instance.hasChildren) instance.build = init(instance.build, true);
        return instance;
      });
    };

    return init(builds);
  }

  /**
   * Run all build targets
   * @param {Array} builds
   * @param {Function} fn(err, filepaths)
   */
  run (builds, fn) {
    this.building = true;

    // Execute builds in sequence
    series(builds.map((build) => callable(build, 'run')),
      (err, results) => {
        if (err) return fn(err);

        this.building = false;
        fn(null, compact(flatten(results)).map((result) => result.filepath));
      }
    );
  }

  /**
   * Run the script defined in config 'script'
   */
  executeScript () {
    let hasErrored = false;
    let args, command, script;

    if (this.config.runtimeOptions.script && (script = this.config.script)) {
      script = script.split(' ');
      command = script.shift();
      args = script;

      print('executing script...', 1);
      debug(`execute: ${strong(this.config.script)}`, 3);

      script = spawn(command, args, { cwd: process.cwd() });

      script.stdout.on('data', (data) => {
        process.stdout.write(data.toString());
      });

      script.stderr.on('data', (data) => {
        process.stderr.write(data.toString());
        hasErrored = true;
      });

      script.on('close', (code) => {
        if (hasErrored) process.stderr.write(BELL);
      });
    }
  }

  /**
   * Handle cache changes
   * @param {File} file
   */
  onFileCacheChange (file) {
    const now = new Date();
    const builds = this.builds.filter((build) => build.hasFile(file));
    // Determine if any changes to app server code that needs a restart
    const servers = builds.filter((build) => build.isAppServer);

    if (!this.building) {
      print(`[${now.toLocaleTimeString()}] ${chalk.yellow('changed')} ${strong(path.relative(process.cwd(), file.filepath))}`, 0);

      start('watch');

      this.run(builds, (err, filepaths) => {
        // Don't throw
        if (err) return error(err, 2, false);
        if (serverfarm) {
          // Trigger partial refresh if only 1 css file, full reload if not
          const filepath = (filepaths.length == 1 && path.extname(filepaths[0]) == '.css')
            ? filepaths[0]
            : 'foo.js';

          // Refresh browser
          if (!servers.length) {
            serverfarm.refresh(path.basename(filepath));
          } else {
            // Restart app server
            serverfarm.restart((err) => {
              if (err) { /* ignore */ }
              // Refresh browser
              serverfarm.refresh(path.basename(filepath));
            });
          }
        }
        print(`done in ${chalk.cyan((stop('watch') / 1000) + 's')}`, 0);
        // Run test script
        this.executeScript();
      });
    }
  }
}<|endoftext|>


<commit_before>/*jslint vars: true, nomen: true, plusplus: true, white: true */
var Board = (function() {

'use strict';

// `rowSpan` indicates the max. vertical size of an individual element
function Board(colCount, rowSpan) {
	this.colCount = colCount;
	this.rowSpan = rowSpan;

	this.matrix = []; // two-dimensional array; rows * columns
	this.extend();
}
Board.prototype.add = function(obj, width, height) {
	var rowIndex, colIndex, span, fit;
	for(rowIndex = 0; rowIndex < this.matrix.length; rowIndex++) {
		if(rowIndex % this.rowSpan === 0) { // row spans are processed together
			for(colIndex = 0; colIndex < this.colCount; colIndex++) {
				fit = this.put(obj, rowIndex, colIndex, width, height);
				if(fit) {
					return;
				} else if(height === 1) { // larger elements are top-aligned
					for(span = 0; span < this.rowSpan; span++) {
						var _rowIndex = rowIndex + span;
						fit = this.put(obj, _rowIndex, colIndex, width, height);
						if(fit) {
							return;
						}
					}
				}
			}
		}
	}
	// try again
	this.extend();
	return this.add.apply(this, arguments);
};
// mark the given area's slots as occupied by the given object
// returns `false` if the area is already (partially) occupied
// NB: does not support irregular shapes
Board.prototype.put = function(obj, top, left, width, height) { // XXX: almost entirely duplicates `checkFit`
	var fit = this.checkFit(top, left, width, height);
	if(!fit) {
		return false;
	}

	var bottom = top + height;
	var right = left + width;
	var i, j;
	for(i = top; i < bottom; i++) {
		var row = this.matrix[i];
		for(j = left; j < right; j++) {
			row[j] = obj;
		}
	}
	return true;
};
// check whether the given area's slots are unoccupied
Board.prototype.checkFit = function(top, left, width, height) {
	if(left + width > this.colCount) {
		return false;
	}

	var bottom = top + height;
	var right = left + width;
	var i, j;
	for(i = top; i < bottom; i++) {
		var row = this.matrix[i];
		for(j = left; j < right; j++) {
			if(row[j] !== undefined) {
				return false;
			}
		}
	}
	return true;
};
// add a set of rows (based on row span)
Board.prototype.extend = function() {
	var i;
	for(i = 0; i < this.rowSpan; i++) {
		var row = new Array(this.colCount);
		this.matrix.push(row);
	}
};

return Board;

}());
<commit_msg>simplified matrix traversal<commit_after>/*jslint vars: true, plusplus: true, white: true */
var Board = (function() {

'use strict';

// `rowSpan` indicates the max. vertical size of an individual element
function Board(colCount, rowSpan) {
	this.colCount = colCount;
	this.rowSpan = rowSpan;

	this.matrix = []; // two-dimensional array; rows * columns
	this.extend();
}
Board.prototype.add = function(obj, width, height) {
	var rowIndex, colIndex, span, fit;
	for(rowIndex = 0; rowIndex < this.matrix.length; rowIndex++) {
		if(rowIndex % this.rowSpan === 0) { // row spans are processed together
			for(colIndex = 0; colIndex < this.colCount; colIndex++) {
				for(span = 0; span < this.rowSpan; span++) {
					if(span === 0 || height === 1) { // larger elements are top-aligned
						fit = this.put(obj, rowIndex + span, colIndex, width, height);
						if(fit) {
							return;
						}
					}
				}
			}
		}
	}
	// try again
	this.extend();
	return this.add.apply(this, arguments);
};
// mark the given area's slots as occupied by the given object
// returns `false` if the area is already (partially) occupied
// NB: does not support irregular shapes
Board.prototype.put = function(obj, top, left, width, height) { // XXX: almost entirely duplicates `checkFit`
	var fit = this.checkFit(top, left, width, height);
	if(!fit) {
		return false;
	}

	var bottom = top + height;
	var right = left + width;
	var i, j;
	for(i = top; i < bottom; i++) {
		var row = this.matrix[i];
		for(j = left; j < right; j++) {
			row[j] = obj;
		}
	}
	return true;
};
// check whether the given area's slots are unoccupied
Board.prototype.checkFit = function(top, left, width, height) {
	if(left + width > this.colCount) {
		return false;
	}

	var bottom = top + height;
	var right = left + width;
	var i, j;
	for(i = top; i < bottom; i++) {
		var row = this.matrix[i];
		for(j = left; j < right; j++) {
			if(row[j] !== undefined) {
				return false;
			}
		}
	}
	return true;
};
// add a set of rows (based on row span)
Board.prototype.extend = function() {
	var i;
	for(i = 0; i < this.rowSpan; i++) {
		var row = new Array(this.colCount);
		this.matrix.push(row);
	}
};

return Board;

}());
<|endoftext|>


<commit_before>;(function (module) {

	'use strict';

	// validation util functions
	var _assert = {

		'is': function(methods, type) {
			return Object.prototype.toString.call(methods).slice(8, -1) === type;
		},

		// apply type checking to a collection
		'areAll': function(items, type) {

			for(var ith = 0, len = items.length;  ith < len; ith++) {

				if(!this.is(items[ith], type)) {
					return false;
				}
			}

			return true;
		},
	},

	// extend an object with another objects properties/state
	// returns a new object, leaving both methods & parent untouched
	_extend = function(methods, parent) {

		// holds Builder arguments array
		var args,

		// allow us to cache arguments of the initial Builder call
		init = false,

		Builder = function() {

			// if first call, cache arguments
			if(!init) {
				args = arguments;
			}

			// builder is ready
			init = true;

			if(!(this instanceof Builder)) {
				return new Builder();
			}

			this._constructor.apply(this, args);
		};

		// attach parent members
		Builder.prototype = parent;

		// attach all method members to the Builder
		for(var method in methods) {
			if(methods.hasOwnProperty(method)) {
				Builder.prototype[method] = methods[method];
			}
		}

		// when no '_constructor' found, init an empty constructor
		if(!Builder.prototype._constructor) {
			Builder.prototype._constructor = function() { };
		}

		return Builder;
	},

	// ensures the we get 'true' sync behavior
	_async = function(fn) {
		setTimeout(fn, 0);
	},

	// convenience object for throwing helpful errors
	_error = {

		'sub': function() {
			return 'USAGE [ topic:String, object:Object, toCall:String ]';
		},

		'pub': function() {
			return 'UASGE [ topic:String, data:Array[Any...] ]';
		},

		'unsub': function() {
			return 'USAGE [topic:String, oId:Number]';
		},

		'pubError': function(topic, error) {
			return 'Failed to publish to obj on topic "' +
				topic + '" [' + error.message + ']';
		},

		'notAnObject': function() {
			return 'argument to Bugle must be a literal object';
		}
	},

	// apply current sub object and pub args to sub function
	_publishTo = function(topic, data) {

		return function(subscriber) {

			try {
				subscriber
				.fn.apply(
					subscriber.obj,
					data.length? data.concat(topic) : [topic]
				);

			} catch(e) {

				_async(function() {
					throw _error.pubError(topic, e);
				});
			}
		};
	},

	// notify all subscribers of a topic with a message(s)
	_publish = function(topic) {

		var self = this;

		if(_assert.is(topic, 'String')) {

			var args = Array.prototype.slice.call(arguments, 1);

			// publish args to each subscriber on topic
			_async(function() {

				if(self.topics[topic]) {

					var subscribers = self.topics[topic],
					template = _publishTo(topic, args);

					subscribers.forEach(template);
				}
			});

			return true;

		} else {

			throw _error.pub();
		}
	},

	// subscribe a function to a topic
	// with a given scope (defaults to current Bugle instance)
	_subscribe = function(topic, toCall, scope) {

		scope = scope? scope : this;

		// verify that param #1 & #3 are of type String
		var isTopicString = _assert.is(topic, 'String'),

		// scope should be of type Object
		isScopeObject = _assert.is(scope, 'Object');

		if(isTopicString && isScopeObject) {

			if(!this.topics[topic]) {
				this.topics[topic] = [];
			}

			this.topics[topic].push({
				'oId': (++this.oId),
				'obj': scope,
				'fn': toCall
			});

			return this.oId;

		} else {

			throw _error.sub();
		}
	},

	// remove an object from the subscriptions list on a topic with its assigned oId
	_unsubscribe = function(topic, oId) {

		var self = this,

		isTopicString = _assert.is(topic, 'String'),
		isOidNumber = _assert.is(oId, 'Number');

		if(isTopicString && isOidNumber) {

			var subscribers = self.topics[topic];

			if(subscribers) {

				_async(function() {

					subscribers = subscribers.filter(function(subscriber) {
						return subscriber.oId !== oId;
					});

				});

				return true;

			} else {

				return false;
			}

		} else {

			throw _error.unsub();
		}
	};

	function Bugle() {

		//removes the need for 'new' keyword
		if(!(this instanceof Bugle)) {
			return new Bugle();
		}

		// holds topic namespaces along with its subscribers
		this.topics = [];

		// tracking id generated for each new subscription
		this.oId = 0;
	}

	Bugle.prototype = {

		'pub': _publish,

		'sub': _subscribe,

		'unsub': _unsubscribe,

		'extend': function(methods) {
			return _extend(methods, this);
		}
	};

	module['extend'] = function(methods) {

		// check for option arg
		if(methods && Object.keys(methods).length) {

			// verify methods is of type Object
			if(_assert.is(methods, 'Object')) {
				return Bugle().extend(methods);

			} else {

				throw _error.notAnObject();
			}
		}
	}

} )(typeof module !== 'undefined' && module.exports? module.exports : window.Bugle = {});<commit_msg>reduced some code using partial application with ecma5 bind function<commit_after>;(function (module) {

	'use strict';

	// validation util functions
	var _assert = {

		'is': function(methods, type) {
			return Object.prototype.toString.call(methods).slice(8, -1) === type;
		},

		// apply type checking to a collection
		'areAll': function(items, type) {

			for(var ith = 0, len = items.length;  ith < len; ith++) {

				if(!this.is(items[ith], type)) {
					return false;
				}
			}

			return true;
		},
	},

	// extend an object with another objects properties/state
	// returns a new object, leaving both methods & parent untouched
	_extend = function(methods, parent) {

		// holds Builder arguments array
		var args,

		// allow us to cache arguments of the initial Builder call
		init = false,

		Builder = function() {

			// if first call, cache arguments
			if(!init) {
				args = arguments;
			}

			// builder is ready
			init = true;

			if(!(this instanceof Builder)) {
				return new Builder();
			}

			this._constructor.apply(this, args);
		};

		// attach parent members
		Builder.prototype = parent;

		// attach all method members to the Builder
		for(var method in methods) {
			if(methods.hasOwnProperty(method)) {
				Builder.prototype[method] = methods[method];
			}
		}

		// when no '_constructor' found, init an empty constructor
		if(!Builder.prototype._constructor) {
			Builder.prototype._constructor = function() { };
		}

		return Builder;
	},

	// ensures the we get 'true' sync behavior
	_async = function(fn) {
		setTimeout(fn, 0);
	},

	// convenience object for throwing helpful errors
	_error = {

		'sub': function() {
			return 'USAGE [ topic:String, object:Object, toCall:String ]';
		},

		'pub': function() {
			return 'UASGE [ topic:String, data:Array[Any...] ]';
		},

		'unsub': function() {
			return 'USAGE [topic:String, oId:Number]';
		},

		'pubError': function(topic, error) {
			return 'Failed to publish to obj on topic "' +
				topic + '" [' + error.message + ']';
		},

		'notAnObject': function() {
			return 'argument to Bugle must be a literal object';
		}
	},

	// apply current sub object and pub args to sub function
	_dispatch = function(topic, data, subscriber) {
		try {
			var msg = data.length? data.concat(topic) : [topic]
			subscriber.fn.apply(subscriber.obj, msg);
		} catch(e) {
			_async(function() {
				throw _error.pubError(topic, e);
			});
		}
	},

	// notify all subscribers of a topic with a message(s)
	_publish = function(topic) {

		var self = this;

		if(_assert.is(topic, 'String')) {

			var args = Array.prototype.slice.call(arguments, 1),
			channelItem = _dispatch.bind(null, topic, args);

			// publish args to each subscriber on topic
			_async(function() {

				if(self.topics[topic]) {

					var subscribers = self.topics[topic];
					subscribers.forEach(channelItem);
				}
			});

			return true;

		} else {

			throw _error.pub();
		}
	},

	// subscribe a function to a topic
	// with a given scope (defaults to current Bugle instance)
	_subscribe = function(topic, toCall, scope) {

		scope = scope? scope : this;

		// verify that param #1 & #3 are of type String
		var isTopicString = _assert.is(topic, 'String'),

		// scope should be of type Object
		isScopeObject = _assert.is(scope, 'Object');

		if(isTopicString && isScopeObject) {

			if(!this.topics[topic]) {
				this.topics[topic] = [];
			}

			this.topics[topic].push({
				'oId': (++this.oId),
				'obj': scope,
				'fn': toCall
			});

			return this.oId;

		} else {

			throw _error.sub();
		}
	},

	// remove an object from the subscriptions list on a topic with its assigned oId
	_unsubscribe = function(topic, oId) {

		var self = this,

		isTopicString = _assert.is(topic, 'String'),
		isOidNumber = _assert.is(oId, 'Number');

		if(isTopicString && isOidNumber) {

			var subscribers = self.topics[topic];

			if(subscribers) {

				_async(function() {

					subscribers = subscribers.filter(function(subscriber) {
						return subscriber.oId !== oId;
					});

				});

				return true;

			} else {

				return false;
			}

		} else {

			throw _error.unsub();
		}
	};

	function Bugle() {

		//removes the need for 'new' keyword
		if(!(this instanceof Bugle)) {
			return new Bugle();
		}

		// holds topic namespaces along with its subscribers
		this.topics = [];

		// tracking id generated for each new subscription
		this.oId = 0;
	}

	Bugle.prototype = {

		'pub': _publish,

		'sub': _subscribe,

		'unsub': _unsubscribe,

		'extend': function(methods) {
			return _extend(methods, this);
		}
	};

	module['extend'] = function(methods) {

		// check for option arg
		if(methods && Object.keys(methods).length) {

			// verify methods is of type Object
			if(_assert.is(methods, 'Object')) {
				return Bugle().extend(methods);

			} else {

				throw _error.notAnObject();
			}
		}
	}

} )(typeof module !== 'undefined' && module.exports? module.exports : window.Bugle = {});<|endoftext|>


<commit_before>'use strict';

var _ = require('underscore');
var fm = require('front-matter');
var fs = require('fs');
var handlebars = require('handlebars');
var marked = require('marked');
var moment = require('moment');

var config = require('./config.json');
var utils = require('./utils');

var setPageTitle = function (title) {
    return title + ' - ' + config.author;
};

var siteData = {
    posts: [],
    pages: [],
    archive: [],
    tags: [],
    navigation: []
};

var createPage = function (data) {
    var html = template(data.pageData);
    var layout = fs.readFile(config.path.layouts + data.layout + '.html', 'utf-8');
    var template = handlebars.compile(layout);

    mkdirp(data.path, function (err) {
        if (err) return console.log(err);

        fs.writeFileSync(data.path + 'index.html', html, function (err) {
            if (err) return err;
        });
    });
}

function build() {
    readMarkdownFiles();
    createAuxData();
    createAllPages();
};

function readMarkdownFiles() {

    if (utils.directoryExists(config.path.posts)) {
        fs.readdirSync(config.path.posts).forEach(function (file) {
            if (file.split('.')[1] !== 'md') return;

            var data = fm(fs.readFileSync(config.path.posts + file, 'utf8'));
            var post = data.attributes;

            post.year = moment(post.date).format('YYYY');
            post.Date = moment(post.date).format('MMM YYYY');
            post.shortDate = moment(post.date).format('DD MM');
            post.content = marked(data.body);

            _.each(post.tags, function (tag) {
                siteData.tags.push({
                    post: post,
                    tag: tag
                });
            });
            siteData.posts.push(post);
        });
    }
    if (utils.directoryExists(config.path.pages)) {
        fs.readdirSync(config.path.pages).forEach(function (file) {
            if (file.split('.')[1] !== 'md') return;

            var data = fm(fs.readFileSync(config.path.pages + file, 'utf8'));
            var page = data.attributes;

            page.content = marked(data.body);
            siteData.pages.push(page);
        });
    }
}

function createAuxData() {
    siteData.posts = _.sortBy(siteData.posts, 'date').reverse();
    siteData.recentPosts = siteData.posts.slice(0, config.recentPostLimit);

    var postsByTag = _.groupBy(siteData.tags, 'tag');
    siteData.tags = [];

    _.mapObject(postsByTag, function (val, key) {
        siteData.tags.push({
            name: key,
            posts: val
        });
    });

    var postsByYear = _.groupBy(siteData.posts, 'year');
    _.mapObject(postsByYear, function (val, key) {
        siteData.archive.push({
            posts: val,
            year: key
        });
    });

    siteData.archive.reverse();

    _.each(siteData.pages, function (page) {
        if (page.navigation) {
            siteData.navigation.push({
                active: false,
                order: page.order,
                slug: page.slug,
                title: page.navigationTitle,
                url: (page.slug === 'home') ? '/' : '/' + page.slug + '/'
            });
        }
    });
    siteData.navigation = _.sortBy(siteData.navigation, 'order');
}

function createAllPages() {

    _.each(siteData.pages, function (page) {
        var pageData = {
            archive: siteData.archive,
            config: config,
            navigation: siteData.navigation,
            page: page,
            recentPosts: siteData.recentPosts
        };

        _.each(siteData.navigation, function (item) {
            item.active = (item.slug == page.slug) ? true : false;
        });

        if (page.slug === 'home') {
            var path = config.path.dist;
            pageData.pageTitle = setPageTitle(config.siteTitle);
            pageData.showRecent = true;
            pageData.isHome = true;
        } else {
            var path = config.path.dist + page.slug + '/';
            pageData.pageTitle = setPageTitle(page.navigationTitle);
        }

        createPage({
            layout: page.layout,
            pageData: pageData,
            path: path
        });
    });

    _.each(siteData.posts, function (post) {
        var pageData = {
            config: config,
            navigation: siteData.navigation,
            pageTitle: setPageTitle(post.title),
            post: post,
            recentPosts: siteData.recentPosts
        };

        _.forEach(siteData.navigation, function (item) {
            item.active = false;
        });

        createPage({
            layout: post.layout,
            path: config.dist + post.year + '/' + post.slug + '/',
            pageData: pageData
        });
    });

    _.each(siteData.tags, function (tag) {
        var pageData = {
            config: config,
            navigation: siteData.navigation,
            pageTitle: setPageTitle('Tag: ' + tag.name),
            recentPosts: siteData.recentPosts,
            tag: tag
        };

        createPage({
            layout: 'tag',
            pageData: pageData,
            path: config.path.dist + '/tag/' + tag.name + '/'
        });
    });
}

module.exports = build;<commit_msg>changed vars so that templates is defined before called<commit_after>'use strict';

var _ = require('underscore');
var fm = require('front-matter');
var fs = require('fs');
var handlebars = require('handlebars');
var marked = require('marked');
var moment = require('moment');

var config = require('./config.json');
var utils = require('./utils');

var setPageTitle = function (title) {
    return title + ' - ' + config.author;
};

var siteData = {
    posts: [],
    pages: [],
    archive: [],
    tags: [],
    navigation: []
};

var createPage = function (data) {
    var layout = fs.readFile(config.path.layouts + data.layout + '.html', 'utf-8');
    var template = handlebars.compile(layout);
    var html = template(data.pageData);

    mkdirp(data.path, function (err) {
        if (err) return console.log(err);

        fs.writeFileSync(data.path + 'index.html', html, function (err) {
            if (err) return err;
        });
    });
}

function build() {
    readMarkdownFiles();
    createAuxData();
    createAllPages();
};

function readMarkdownFiles() {

    if (utils.directoryExists(config.path.posts)) {
        fs.readdirSync(config.path.posts).forEach(function (file) {
            if (file.split('.')[1] !== 'md') return;

            var data = fm(fs.readFileSync(config.path.posts + file, 'utf8'));
            var post = data.attributes;

            post.year = moment(post.date).format('YYYY');
            post.Date = moment(post.date).format('MMM YYYY');
            post.shortDate = moment(post.date).format('DD MM');
            post.content = marked(data.body);

            _.each(post.tags, function (tag) {
                siteData.tags.push({
                    post: post,
                    tag: tag
                });
            });
            siteData.posts.push(post);
        });
    }
    if (utils.directoryExists(config.path.pages)) {
        fs.readdirSync(config.path.pages).forEach(function (file) {
            if (file.split('.')[1] !== 'md') return;

            var data = fm(fs.readFileSync(config.path.pages + file, 'utf8'));
            var page = data.attributes;

            page.content = marked(data.body);
            siteData.pages.push(page);
        });
    }
}

function createAuxData() {
    siteData.posts = _.sortBy(siteData.posts, 'date').reverse();
    siteData.recentPosts = siteData.posts.slice(0, config.recentPostLimit);

    var postsByTag = _.groupBy(siteData.tags, 'tag');
    siteData.tags = [];

    _.mapObject(postsByTag, function (val, key) {
        siteData.tags.push({
            name: key,
            posts: val
        });
    });

    var postsByYear = _.groupBy(siteData.posts, 'year');
    _.mapObject(postsByYear, function (val, key) {
        siteData.archive.push({
            posts: val,
            year: key
        });
    });

    siteData.archive.reverse();

    _.each(siteData.pages, function (page) {
        if (page.navigation) {
            siteData.navigation.push({
                active: false,
                order: page.order,
                slug: page.slug,
                title: page.navigationTitle,
                url: (page.slug === 'home') ? '/' : '/' + page.slug + '/'
            });
        }
    });
    siteData.navigation = _.sortBy(siteData.navigation, 'order');
}

function createAllPages() {

    _.each(siteData.pages, function (page) {
        var pageData = {
            archive: siteData.archive,
            config: config,
            navigation: siteData.navigation,
            page: page,
            recentPosts: siteData.recentPosts
        };

        _.each(siteData.navigation, function (item) {
            item.active = (item.slug == page.slug) ? true : false;
        });

        if (page.slug === 'home') {
            var path = config.path.dist;
            pageData.pageTitle = setPageTitle(config.siteTitle);
            pageData.showRecent = true;
            pageData.isHome = true;
        } else {
            var path = config.path.dist + page.slug + '/';
            pageData.pageTitle = setPageTitle(page.navigationTitle);
        }

        createPage({
            layout: page.layout,
            pageData: pageData,
            path: path
        });
    });

    _.each(siteData.posts, function (post) {
        var pageData = {
            config: config,
            navigation: siteData.navigation,
            pageTitle: setPageTitle(post.title),
            post: post,
            recentPosts: siteData.recentPosts
        };

        _.forEach(siteData.navigation, function (item) {
            item.active = false;
        });

        createPage({
            layout: post.layout,
            path: config.dist + post.year + '/' + post.slug + '/',
            pageData: pageData
        });
    });

    _.each(siteData.tags, function (tag) {
        var pageData = {
            config: config,
            navigation: siteData.navigation,
            pageTitle: setPageTitle('Tag: ' + tag.name),
            recentPosts: siteData.recentPosts,
            tag: tag
        };

        createPage({
            layout: 'tag',
            pageData: pageData,
            path: config.path.dist + '/tag/' + tag.name + '/'
        });
    });
}

module.exports = build;<|endoftext|>


<commit_before>var tools         = require('koapp');
var shell         = require('shelljs');
var fs            = require('fs');
var async         = require('async');
var _             = require('lodash');
var jsonfile      = require('jsonfile');
var chalk         = require('chalk');
var data          = {};
var platform      = "";
var specificDeps  = {
    'ios': {'dep':'https://github.com/apache/cordova-plugins.git#wkwebview-engine-localhost', 'version':'@4.0.0'},
    'android': {'dep':'cordova-plugin-crosswalk-webview@1.7','version':'@5.0.0'}
};
var commandData = {};
var debugMode;

module.exports = {
    build : build,
    help  : help
};

function build(debug, projectName, platform, options) {
    if (!projectName) return tools.debugLog('Project name is mandatory', debug);
    if (!platform) return tools.debugLog('Platform is mandatory', debug);
    if (platform !== 'ios' && platform !== 'android' && platform !== 'none') return tools.debugLog('Invalid platform. Please choose between "ios" or "android".', debug);

    debugMode   = debug;
    commandData = buildData(options);

    jsonfile.readFile(`${commandData.repo}/www/core/structure.json`, function(err, obj) {
        if (err) return tools.debugLog(chalk.red(`\nError reading file structure.json. Please make sure the folder "${commandData.repo}" exists in your project folder.\n`), debugMode);

        var cordova = `cordova create ${projectName} ${obj.packageName || "com.kingofapp.sampleApp"} "${(obj.name || "sampleApp")}" --link-to=${commandData.repo}/www`;
        data = obj;

        /* cordova was having problems executing asynchronously
          shell.exec(cordova, function(err) {
           if (err) return tools.debugLog(chalk.red(`\n${projectName} project already exists. Please delete the folder or use another name.\n`), debugMode);

           shell.cd(projectName);
           var functions = buildSteps(platform, projectName, options);
           async.series(functions, function(err, result) {
           if (err) return tools.debugLog(err, debugMode);

           tools.debugLog(chalk.green("Done!"), debugMode);
           });
           });
       */

        var cordovaBuildExec = shell.exec(cordova, { async: false });
        if (cordovaBuildExec.stderr) return tools.debugLog(cordovaBuildExec.stderr, debug);

        shell.cd(projectName);
        var functions = buildSteps(platform, projectName, options);
        async.series(functions, function(err, result) {
            if (err) return tools.debugLog(err, debugMode);

            tools.debugLog(chalk.green("Done!"), debugMode);
        });
    });
}

// This function is prepared to handle more options in the future
function buildData(options) {
    var commandData = {
        repo: "com.kingofapp.visualizer"
    };

    if (options.indexOf('--dev') !== -1) commandData.repo += ".dev";
    if (options.indexOf('--dist') !== -1) {
        shell.mkdir('-p', `${commandData.repo}/dist`);
        shell.rm('-rf', `${commandData.repo}/www/*`);
        shell.mv('-rf', `${commandData.repo}/dist`, `${commandData.repo}/www`);
    }

    return commandData;
}

function buildSteps(platform, projectName, options) {
    var functions = [
        addCordovaPreferences,
        _.partial(addCordovaPlugins, platform),
        _.partial(addPlatform, platform)
    ];

    if (options.indexOf('--no-image') === -1) functions.push(_.partial(addSplashAndIcon, projectName));

    return functions;
}

function addSplashAndIcon(projectName, callback) {
    tools.debugLog(chalk.green("Generating icon and splash..."), debugMode);

    shell.cp('-f', `../${commandData.repo}/www/images/icon.png`, 'icon.png');
    shell.cp('-f', `../${commandData.repo}/www/images/splash.png`, 'splash.png');
    async.parallel([
        _.partial(shell.exec, 'cordova-icon'),
        _.partial(shell.exec, 'cordova-splash'),
        ], function (err, data) {
            if (err && err.indexOf('ENOENT') > -1) {
                return callback('Error executing ImageMagick. Check the Koapp-cli documentation to learn how to fix this problem (https://github.com/KingofApp/koapp-cli).');
            }

            shell.rm(['splash.png', 'icon.png']);
            shell.cd('..');
            callback(err, data);
   });
}

//Add cordova preferences
function addCordovaPreferences(callback) {
    tools.debugLog(chalk.green("Adding cordova Dependencies..."), debugMode);

    fs.readFile('config.xml', function(err, fileData) {
        if (fileData) {
            var output = cleanBody(fileData.toString());

            fs.writeFile('config.xml', output, function(err) {
                if (err) {
                    tools.debugLog(chalk.red('\nError writing into config.xml file. Please make sure you initialized a project and you are in the right folder.\n'), debugMode);
                    callback(err);
                }

                callback(null);
            });
        } else {
            tools.debugLog(chalk.red('\nError reading config.xml. Please make sure you initialized a project and you are in the right folder.\n'), debugMode);
            callback(err);
        }
    });
}

function cleanBody(body){
    var line = 3;
    var preferences     = '  <access origin="*" />\n' +
        '  <allow-navigation href="*" /> \n' +
        '  <preference name="AutoHideSplashScreen" value="false" />\n' +
        '  <preference name="SplashScreenDelay" value="10000" />\n' +
        '  <preference name="ShowSplashScreenSpinner" value="false" />\n' +
        '  <preference name="FadeSplashScreen" value="true" />\n' +
        '  <preference name="FadeSplashScreenDuration" value="1" />\n' +
        '  <preference name="target-device" value="handset" />';
    var localServer    = '  <content src="http://localhost:56969" />\n';
    var result = body;
    result = result.replace('<platform name="ios">', '<platform name="ios">\n      ' + localServer);

    result = result.split('\n');
    result.splice(line,0,preferences);
    result = result.filter(function(str){ return str; });
    return result.join('\n');
}

//Add particular cordova plugins
function addCordovaPlugins(platform, callback) {
    tools.debugLog(chalk.green('Adding cordova plugins...'));

    var plugins = ['cordova-plugin-device', 'cordova-plugin-geolocation', 'cordova-plugin-console', 'cordova-plugin-dialogs', 'cordova-plugin-globalization', 'cordova-plugin-statusbar', 'cordova-plugin-splashscreen', 'cordova-plugin-inappbrowser'];

    if (['android', 'ios'].indexOf(platform) !== -1) plugins.push(specificDeps[platform]['dep']);

    plugins = _.union(plugins, getCordovaDeps(data.modules), getCordovaDeps(data.services));
    var commands = _.map(plugins, function(plugin) {
        return `cordova plugin add ${plugin}`;
    });

    function executeCommand(command, callback) {
        var result = shell.exec(command, { async: false });

        if (result.indexOf('Saved plugin info for') > -1) callback(null, result.stdout);
        else callback(result.stderr);
    }

    async.each(commands, executeCommand, callback);
}

function addPlatform(platform, callback) {
    tools.debugLog(chalk.green('Adding platform...'), debugMode);

    var platformVersion = platform + specificDeps[platform]['version'];
    var addPlatformCommand = `cordova platform add ${platformVersion}`;
    shell.exec(addPlatformCommand, function(code, output) {
        callback(code, output);
    });
}

function getCordovaDeps(items) {
    return tools.getUniqueItems(items, 'deps');
}

function help() {
    var command = chalk.yellow('koapp build <projectName> <platform> [--dev || --no-image]');
    tools.debugLog(command, true);
    tools.debugLog('' , true);
    tools.debugLog('Build your Cordova project with all its dependencies for the selected platform', true);
    tools.debugLog('', true);
}
<commit_msg>Remove www and rename dist folder if --dist option is passed<commit_after>var tools         = require('koapp');
var shell         = require('shelljs');
var fs            = require('fs');
var async         = require('async');
var _             = require('lodash');
var jsonfile      = require('jsonfile');
var chalk         = require('chalk');
var data          = {};
var platform      = "";
var specificDeps  = {
    'ios': {'dep':'https://github.com/apache/cordova-plugins.git#wkwebview-engine-localhost', 'version':'@4.0.0'},
    'android': {'dep':'cordova-plugin-crosswalk-webview@1.7','version':'@5.0.0'}
};
var commandData = {};
var debugMode;

module.exports = {
    build : build,
    help  : help
};

function build(debug, projectName, platform, options) {
    if (!projectName) return tools.debugLog('Project name is mandatory', debug);
    if (!platform) return tools.debugLog('Platform is mandatory', debug);
    if (platform !== 'ios' && platform !== 'android' && platform !== 'none') return tools.debugLog('Invalid platform. Please choose between "ios" or "android".', debug);

    debugMode   = debug;
    commandData = buildData(options);

    jsonfile.readFile(`${commandData.repo}/www/core/structure.json`, function(err, obj) {
        if (err) return tools.debugLog(chalk.red(`\nError reading file structure.json. Please make sure the folder "${commandData.repo}" exists in your project folder.\n`), debugMode);

        var cordova = `cordova create ${projectName} ${obj.packageName || "com.kingofapp.sampleApp"} "${(obj.name || "sampleApp")}" --link-to=${commandData.repo}/www`;
        data = obj;

        var cordovaBuildExec = shell.exec(cordova, { async: false });
        if (cordovaBuildExec.stderr) return tools.debugLog(cordovaBuildExec.stderr, debug);

        shell.cd(projectName);
        var functions = buildSteps(platform, projectName, options);
        async.series(functions, function(err, result) {
            if (err) return tools.debugLog(err, debugMode);

            if (options.indexOf('--dist') !== -1) {
                shell.rm('-rf', `${commandData.repo}/www`);
                shell.mv('-f', `${commandData.repo}/dist`, `${commandData.repo}/www`);
            }

            tools.debugLog(chalk.green("Done!"), debugMode);
        });
    });
}

// This function is prepared to handle more options in the future
function buildData(options) {
    var commandData = {
        repo: "com.kingofapp.visualizer"
    };

    if (options.indexOf('--dev') !== -1) commandData.repo += ".dev";
    if (options.indexOf('--dist') !== -1) {
        shell.mkdir('-p', `${commandData.repo}/dist`);
    }

    return commandData;
}

function buildSteps(platform, projectName, options) {
    var functions = [
        addCordovaPreferences,
        _.partial(addCordovaPlugins, platform),
        _.partial(addPlatform, platform)
    ];

    if (options.indexOf('--no-image') === -1) functions.push(_.partial(addSplashAndIcon, projectName));

    return functions;
}

function addSplashAndIcon(projectName, callback) {
    tools.debugLog(chalk.green("Generating icon and splash..."), debugMode);

    shell.cp('-f', `../${commandData.repo}/www/images/icon.png`, 'icon.png');
    shell.cp('-f', `../${commandData.repo}/www/images/splash.png`, 'splash.png');
    async.parallel([
        _.partial(shell.exec, 'cordova-icon'),
        _.partial(shell.exec, 'cordova-splash'),
        ], function (err, data) {
            if (err && err.indexOf('ENOENT') > -1) {
                return callback('Error executing ImageMagick. Check the Koapp-cli documentation to learn how to fix this problem (https://github.com/KingofApp/koapp-cli).');
            }

            shell.rm(['splash.png', 'icon.png']);
            shell.cd('..');
            callback(err, data);
   });
}

//Add cordova preferences
function addCordovaPreferences(callback) {
    tools.debugLog(chalk.green("Adding cordova Dependencies..."), debugMode);

    fs.readFile('config.xml', function(err, fileData) {
        if (fileData) {
            var output = cleanBody(fileData.toString());

            fs.writeFile('config.xml', output, function(err) {
                if (err) {
                    tools.debugLog(chalk.red('\nError writing into config.xml file. Please make sure you initialized a project and you are in the right folder.\n'), debugMode);
                    callback(err);
                }

                callback(null);
            });
        } else {
            tools.debugLog(chalk.red('\nError reading config.xml. Please make sure you initialized a project and you are in the right folder.\n'), debugMode);
            callback(err);
        }
    });
}

function cleanBody(body){
    var line = 3;
    var preferences     = '  <access origin="*" />\n' +
        '  <allow-navigation href="*" /> \n' +
        '  <preference name="AutoHideSplashScreen" value="false" />\n' +
        '  <preference name="SplashScreenDelay" value="10000" />\n' +
        '  <preference name="ShowSplashScreenSpinner" value="false" />\n' +
        '  <preference name="FadeSplashScreen" value="true" />\n' +
        '  <preference name="FadeSplashScreenDuration" value="1" />\n' +
        '  <preference name="target-device" value="handset" />';
    var localServer    = '  <content src="http://localhost:56969" />\n';
    var result = body;
    result = result.replace('<platform name="ios">', '<platform name="ios">\n      ' + localServer);

    result = result.split('\n');
    result.splice(line,0,preferences);
    result = result.filter(function(str){ return str; });
    return result.join('\n');
}

//Add particular cordova plugins
function addCordovaPlugins(platform, callback) {
    tools.debugLog(chalk.green('Adding cordova plugins...'));

    var plugins = ['cordova-plugin-device', 'cordova-plugin-geolocation', 'cordova-plugin-console', 'cordova-plugin-dialogs', 'cordova-plugin-globalization', 'cordova-plugin-statusbar', 'cordova-plugin-splashscreen', 'cordova-plugin-inappbrowser'];

    if (['android', 'ios'].indexOf(platform) !== -1) plugins.push(specificDeps[platform]['dep']);

    plugins = _.union(plugins, getCordovaDeps(data.modules), getCordovaDeps(data.services));
    var commands = _.map(plugins, function(plugin) {
        return `cordova plugin add ${plugin}`;
    });

    function executeCommand(command, callback) {
        var result = shell.exec(command, { async: false });

        if (result.indexOf('Saved plugin info for') > -1) callback(null, result.stdout);
        else callback(result.stderr);
    }

    async.each(commands, executeCommand, callback);
}

function addPlatform(platform, callback) {
    tools.debugLog(chalk.green('Adding platform...'), debugMode);

    var platformVersion = platform + specificDeps[platform]['version'];
    var addPlatformCommand = `cordova platform add ${platformVersion}`;
    shell.exec(addPlatformCommand, function(code, output) {
        callback(code, output);
    });
}

function getCordovaDeps(items) {
    return tools.getUniqueItems(items, 'deps');
}

function help() {
    var command = chalk.yellow('koapp build <projectName> <platform> [--dev || --no-image]');
    tools.debugLog(command, true);
    tools.debugLog('' , true);
    tools.debugLog('Build your Cordova project with all its dependencies for the selected platform', true);
    tools.debugLog('', true);
}
<|endoftext|>


<commit_before>
module.exports = exports = build

exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'

/**
 * Module dependencies.
 */

var which = require('which')
  , win = process.platform == 'win32'

function build (gyp, argv, callback) {

  var command

  if (win) {
    // invoke "msbuild"
    command = 'msbuild'
  } else {
    // invoke "make"
    command = 'make'
  }

  // First make sure we have the build command in the PATH
  which(command, function (err, execPath) {
    if (err) return callback(err)
    gyp.verbose('which ' + command, execPath)

    var args = []

    // Enable Verbose build
    if (gyp.opts.verbose) {
      args.push('V=1')
    }

    // Specify the build type, Release by default
    args.push('BUILDTYPE=' + (gyp.opts.debug ? 'Debug' : 'Release'))

    var proc = gyp.spawn(command, args)
    proc.on('exit', function (code, signal) {
      if (code !== 0) {
        return callback(new Error('`' + command + '` failed with exit code: ' + code))
      }
      if (signal) {
        return callback(new Error('`' + command + '` got signal: ' + signal))
      }
      callback()
    })
  })
}
<commit_msg>Fix build command usage on Windows.<commit_after>
module.exports = exports = build

/**
 * Module dependencies.
 */

var which = require('which')
  , win = process.platform == 'win32'

exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'

function build (gyp, argv, callback) {

  var command

  if (win) {
    // invoke "msbuild"
    command = 'msbuild'
  } else {
    // invoke "make"
    command = 'make'
  }

  // First make sure we have the build command in the PATH
  which(command, function (err, execPath) {
    if (err) return callback(err)
    gyp.verbose('which ' + command, execPath)

    var args = []

    // Enable Verbose build
    if (gyp.opts.verbose) {
      args.push('V=1')
    }

    // Specify the build type, Release by default
    args.push('BUILDTYPE=' + (gyp.opts.debug ? 'Debug' : 'Release'))

    var proc = gyp.spawn(command, args)
    proc.on('exit', function (code, signal) {
      if (code !== 0) {
        return callback(new Error('`' + command + '` failed with exit code: ' + code))
      }
      if (signal) {
        return callback(new Error('`' + command + '` got signal: ' + signal))
      }
      callback()
    })
  })
}
<|endoftext|>