<commit_before>
  /***
   * @package Core
   * @description Internal utility and common methods.
   ***/

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // Internal toString
  var internalToString = object.prototype.toString;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // Type check methods need a way to be accessed dynamically outside global context.
  var typeChecks = {};

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class initializers and class helpers

  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');

  var isArray    = buildClassCheck(ClassNames[0]);
  var isBoolean  = buildClassCheck(ClassNames[1]);
  var isDate     = buildClassCheck(ClassNames[2]);
  var isNumber   = buildClassCheck(ClassNames[4]);
  var isString   = buildClassCheck(ClassNames[5]);
  var isRegExp   = buildClassCheck(ClassNames[6]);

  function isFunction(obj) {
    return typeof obj === 'function';
  }

  function buildClassCheck(name) {
    var type, fn;
    if(/String|Number|Boolean/.test(name)) {
      type = name.toLowerCase();
    }
    fn = (name === 'Array' && array.isArray) || function(obj, klass) {
      if(type && typeof obj === type) {
        return true;
      }
      klass = klass || className(obj);
      return klass === '[object '+name+']';
    }
    typeChecks[name] = fn;
    return fn;
  }

  function className(obj) {
    return internalToString.call(obj);
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      },
      'sugarRestore': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          defineProperty(target, name, m.method);
        });
      },
      'sugarRevert': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          if(m.existed) {
            defineProperty(target, name, m.original);
          } else {
            delete target[name];
          }
        });
      }
    });
  }

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      var original = extendee[name];
      var existed  = hasOwnProperty(extendee, name);
      if(typeof override === 'function') {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original, existed: existed };
    });
  }

  function extendSimilar(klass, instance, override, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name, i) {
      fn(methods, name, i);
    });
    extend(klass, instance, override, methods);
  }

  function batchMethodExecute(klass, args, fn) {
    var all = args.length === 0, methods = multiArgs(args), changed = false;
    iterateOverObject(klass['SugarMethods'], function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m.instance ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      var fn;
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        fn = nativeFn;
      } else {
        fn = extendedFn;
      }
      return fn.apply(this, arguments);
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  // Argument helpers

  function multiArgs(args, fn) {
    var result = [], i, len;
    for(i = 0, len = args.length; i < len; i++) {
      result.push(args[i]);
      if(fn) fn.call(args, args[i], i);
    }
    return result;
  }

  function flattenedArgs(obj, fn, from) {
    multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
  }

  function checkCallback(fn) {
    if(!fn || !fn.call) {
      throw new TypeError('Callback is not callable');
    }
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  // Object helpers

  function isObjectPrimitive(obj) {
    // Check for null
    return obj && typeof obj === 'object';
  }

  function isPlainObject(obj, klass) {
    klass = klass || className(obj);
    try {
      // Not own constructor property must be Object
      // This code was borrowed from jQuery.isPlainObject
      if (obj.constructor &&
            !hasOwnProperty(obj, 'constructor') &&
            !hasOwnProperty(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
      }
    } catch (e) {
      // IE8,9 Will throw exceptions on certain host objects.
      return false;
    }
    // === on the constructor is not safe across iframes
    // 'hasOwnProperty' ensures that the object also inherits
    // from Object, which is false for DOMElements in IE.
    return !!obj && klass === '[object Object]' && 'hasOwnProperty' in obj;
  }

  function hasOwnProperty(obj, key) {
    return object['hasOwnProperty'].call(obj, key);
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function simpleRepeat(n, fn) {
    for(var i = 0; i < n; i++) {
      fn(i);
    }
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
    return target;
  }

  // Hash definition

  function Hash(obj) {
    simpleMerge(this, obj);
  };

  Hash.prototype.constructor = object;

  // Number helpers

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  // Used by Number and Date

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  // String helpers

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  function getTrimmableCharacters() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    var result = '';
    if(isUndefined(times)) {
      times = 1;
    }
    while(times-- > 0) {
      result += str;
    }
    return result;
  }

  // RegExp helpers

  function getRegExpFlags(reg, add) {
    var flags = reg.toString().match(/[^/]*$/)[0];
    if(add) {
      flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
    }
    return flags;
  }

  function escapeRegExp(str) {
    if(!isString(str)) str = string(str);
    return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
  }

  // Date helpers

  function callDateGet(d, method) {
    return d['get' + (d._utc ? 'UTC' : '') + method]();
  }

  function callDateSet(d, method, value) {
    return d['set' + (d._utc && method != 'ISOWeek' ? 'UTC' : '') + method](value);
  }

  function extractDurationFromString(str) {
    var match, val, unit;
    match = str.toLowerCase().match(/^(\d+)?\s?(\w+?)s?$/i);
    val = parseInt(match[1]) || 1;
    unit = match[2].slice(0,1).toUpperCase() + match[2].slice(1);
    if(unit.match(/hour|minute|second/i)) {
      unit += 's';
    } else if(unit === 'Year') {
      unit = 'FullYear';
    } else if(unit === 'Day') {
      unit = 'Date';
    }
    return [val, unit];
  }

  // Specialized helpers

  // Used by Array#unique and Object.equal

  function stringify(thing, stack) {
    var type = typeof thing,
        thingIsObject,
        thingIsArray,
        klass, value,
        arr, key, i, len;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass         = internalToString.call(thing)
    thingIsObject = isPlainObject(thing, klass);
    thingIsArray  = isArray(thing, klass);

    if(thing != null && thingIsObject || thingIsArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = thing.valueOf() + string(thing.constructor);
      arr = thingIsArray ? thing : object.keys(thing).sort();
      for(i = 0, len = arr.length; i < len; i++) {
        key = thingIsArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf ? thing.valueOf() : thing);
    }
    return type + klass + value;
  }

  function isEqual(a, b) {
    if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
      return stringify(a) === stringify(b);
    } else {
      return a === b;
    }
  }

  function objectIsMatchedByValue(obj) {
    // Only known objects are matched by value. This is notably excluding functions, DOM Elements, and instances of
    // user-created classes. The latter can arguably be matched by value, but distinguishing between these and
    // host objects -- which should never be compared by value -- is very tricky so not dealing with it here.
    var klass = className(obj);
    return /^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/.test(klass) || isPlainObject(obj, klass);
  }

  // Used by Array#at and String#at

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // Object class methods implemented as instance methods

  function buildObjectInstanceMethods(set, target) {
    extendSimilar(target, true, false, set, function(methods, name) {
      methods[name + (name === 'equal' ? 's' : '')] = function() {
        return object[name].apply(null, [this].concat(multiArgs(arguments)));
      }
    });
  }

  initializeClasses();

<commit_msg>regexp is typeof == 'function' in FF1-2<commit_after>
  /***
   * @package Core
   * @description Internal utility and common methods.
   ***/

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // Internal toString
  var internalToString = object.prototype.toString;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // Type check methods need a way to be accessed dynamically outside global context.
  var typeChecks = {};

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class initializers and class helpers

  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');

  var isArray    = buildClassCheck(ClassNames[0]);
  var isBoolean  = buildClassCheck(ClassNames[1]);
  var isDate     = buildClassCheck(ClassNames[2]);
  var isFunction = buildClassCheck(ClassNames[3]);
  var isNumber   = buildClassCheck(ClassNames[4]);
  var isString   = buildClassCheck(ClassNames[5]);
  var isRegExp   = buildClassCheck(ClassNames[6]);

  function buildClassCheck(name) {
    var type, fn;
    if(/String|Number|Boolean/.test(name)) {
      type = name.toLowerCase();
    }
    fn = (name === 'Array' && array.isArray) || function(obj, klass) {
      if(type && typeof obj === type) {
        return true;
      }
      klass = klass || className(obj);
      return klass === '[object '+name+']';
    }
    typeChecks[name] = fn;
    return fn;
  }

  function className(obj) {
    return internalToString.call(obj);
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      },
      'sugarRestore': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          defineProperty(target, name, m.method);
        });
      },
      'sugarRevert': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          if(m.existed) {
            defineProperty(target, name, m.original);
          } else {
            delete target[name];
          }
        });
      }
    });
  }

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      var original = extendee[name];
      var existed  = hasOwnProperty(extendee, name);
      if(typeof override === 'function') {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original, existed: existed };
    });
  }

  function extendSimilar(klass, instance, override, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name, i) {
      fn(methods, name, i);
    });
    extend(klass, instance, override, methods);
  }

  function batchMethodExecute(klass, args, fn) {
    var all = args.length === 0, methods = multiArgs(args), changed = false;
    iterateOverObject(klass['SugarMethods'], function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m.instance ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      var fn;
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        fn = nativeFn;
      } else {
        fn = extendedFn;
      }
      return fn.apply(this, arguments);
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  // Argument helpers

  function multiArgs(args, fn) {
    var result = [], i, len;
    for(i = 0, len = args.length; i < len; i++) {
      result.push(args[i]);
      if(fn) fn.call(args, args[i], i);
    }
    return result;
  }

  function flattenedArgs(obj, fn, from) {
    multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
  }

  function checkCallback(fn) {
    if(!fn || !fn.call) {
      throw new TypeError('Callback is not callable');
    }
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  // Object helpers

  function isObjectPrimitive(obj) {
    // Check for null
    return obj && typeof obj === 'object';
  }

  function isPlainObject(obj, klass) {
    klass = klass || className(obj);
    try {
      // Not own constructor property must be Object
      // This code was borrowed from jQuery.isPlainObject
      if (obj.constructor &&
            !hasOwnProperty(obj, 'constructor') &&
            !hasOwnProperty(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
      }
    } catch (e) {
      // IE8,9 Will throw exceptions on certain host objects.
      return false;
    }
    // === on the constructor is not safe across iframes
    // 'hasOwnProperty' ensures that the object also inherits
    // from Object, which is false for DOMElements in IE.
    return !!obj && klass === '[object Object]' && 'hasOwnProperty' in obj;
  }

  function hasOwnProperty(obj, key) {
    return object['hasOwnProperty'].call(obj, key);
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function simpleRepeat(n, fn) {
    for(var i = 0; i < n; i++) {
      fn(i);
    }
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
    return target;
  }

  // Hash definition

  function Hash(obj) {
    simpleMerge(this, obj);
  };

  Hash.prototype.constructor = object;

  // Number helpers

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  // Used by Number and Date

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  // String helpers

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  function getTrimmableCharacters() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    var result = '';
    if(isUndefined(times)) {
      times = 1;
    }
    while(times-- > 0) {
      result += str;
    }
    return result;
  }

  // RegExp helpers

  function getRegExpFlags(reg, add) {
    var flags = reg.toString().match(/[^/]*$/)[0];
    if(add) {
      flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
    }
    return flags;
  }

  function escapeRegExp(str) {
    if(!isString(str)) str = string(str);
    return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
  }

  // Date helpers

  function callDateGet(d, method) {
    return d['get' + (d._utc ? 'UTC' : '') + method]();
  }

  function callDateSet(d, method, value) {
    return d['set' + (d._utc && method != 'ISOWeek' ? 'UTC' : '') + method](value);
  }

  function extractDurationFromString(str) {
    var match, val, unit;
    match = str.toLowerCase().match(/^(\d+)?\s?(\w+?)s?$/i);
    val = parseInt(match[1]) || 1;
    unit = match[2].slice(0,1).toUpperCase() + match[2].slice(1);
    if(unit.match(/hour|minute|second/i)) {
      unit += 's';
    } else if(unit === 'Year') {
      unit = 'FullYear';
    } else if(unit === 'Day') {
      unit = 'Date';
    }
    return [val, unit];
  }

  // Specialized helpers

  // Used by Array#unique and Object.equal

  function stringify(thing, stack) {
    var type = typeof thing,
        thingIsObject,
        thingIsArray,
        klass, value,
        arr, key, i, len;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass         = internalToString.call(thing)
    thingIsObject = isPlainObject(thing, klass);
    thingIsArray  = isArray(thing, klass);

    if(thing != null && thingIsObject || thingIsArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = thing.valueOf() + string(thing.constructor);
      arr = thingIsArray ? thing : object.keys(thing).sort();
      for(i = 0, len = arr.length; i < len; i++) {
        key = thingIsArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf ? thing.valueOf() : thing);
    }
    return type + klass + value;
  }

  function isEqual(a, b) {
    if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
      return stringify(a) === stringify(b);
    } else {
      return a === b;
    }
  }

  function objectIsMatchedByValue(obj) {
    // Only known objects are matched by value. This is notably excluding functions, DOM Elements, and instances of
    // user-created classes. The latter can arguably be matched by value, but distinguishing between these and
    // host objects -- which should never be compared by value -- is very tricky so not dealing with it here.
    var klass = className(obj);
    return /^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/.test(klass) || isPlainObject(obj, klass);
  }

  // Used by Array#at and String#at

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // Object class methods implemented as instance methods

  function buildObjectInstanceMethods(set, target) {
    extendSimilar(target, true, false, set, function(methods, name) {
      methods[name + (name === 'equal' ? 's' : '')] = function() {
        return object[name].apply(null, [this].concat(multiArgs(arguments)));
      }
    });
  }

  initializeClasses();

<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

var sshpk = require('sshpk');
var ldap = require('ldapjs');

///--- API

module.exports = {

    add: function addKey(req, res, next) {
        var entry = req.toObject().attributes;
        var log = req.log;
        var key;
        var sdckey = false;

        log.debug({
            dn: req.dn.toString(),
            entry: entry
        }, 'Checking if we need to inject a PKCS attribute');

        var i;
        for (i = 0; i < (entry.objectclass || []).length; i++) {
            if (entry.objectclass[i].toLowerCase() === 'sdckey') {
                sdckey = true;
                break;
            }
        }
        if (!entry.openssh || entry.openssh.length === 0) {
            return next();
        }

        log.debug({
            dn: req.dn.toString(),
            entry: entry,
            sdckey: sdckey
        }, 'Inject?');

        if (!sdckey) {
            return next();
        }

        try {
            // Just in case, fix extra spaces in keys [CAPI-194]:
            key = entry.openssh[0].replace(/(\s){2,}/g, '$1').trim();

            key = sshpk.parseKey(key, 'ssh');

            // Delete the old pkcs attribute, in case it's a lie
            if (entry.pkcs)
                delete req.attributes[req.indexOf('pkcs')];
            req.addAttribute(new ldap.Attribute({
                type: 'pkcs',
                vals: [key.toString('pkcs8')]
            }));

            // If fingerprint is a lie though we have big problems
            var fp = key.fingerprint('md5').toString('hex');
            if (!entry.fingerprint || entry.fingerprint.length === 0) {
                req.addAttribute(new ldap.Attribute({
                    type: 'fingerprint',
                    vals: [fp]
                }));
            } else if (fp !== entry.fingerprint[0]) {
                throw new Error('Calculated fingerprint (' + fp + ') for ' +
                    'this key does not match the given one (' +
                    entry.fingerprint + ')');
            }

        } catch (e) {
            return next(new ldap.InvalidAttributeSyntaxError(e.toString()));
        }

        return next();
    }

};
<commit_msg>CAPI-510 make check finds your lack of curlies disturbing<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

var sshpk = require('sshpk');
var ldap = require('ldapjs');

///--- API

module.exports = {

    add: function addKey(req, res, next) {
        var entry = req.toObject().attributes;
        var log = req.log;
        var key;
        var sdckey = false;

        log.debug({
            dn: req.dn.toString(),
            entry: entry
        }, 'Checking if we need to inject a PKCS attribute');

        var i;
        for (i = 0; i < (entry.objectclass || []).length; i++) {
            if (entry.objectclass[i].toLowerCase() === 'sdckey') {
                sdckey = true;
                break;
            }
        }
        if (!entry.openssh || entry.openssh.length === 0) {
            return next();
        }

        log.debug({
            dn: req.dn.toString(),
            entry: entry,
            sdckey: sdckey
        }, 'Inject?');

        if (!sdckey) {
            return next();
        }

        try {
            // Just in case, fix extra spaces in keys [CAPI-194]:
            key = entry.openssh[0].replace(/(\s){2,}/g, '$1').trim();

            key = sshpk.parseKey(key, 'ssh');

            // Delete the old pkcs attribute, in case it's a lie
            if (entry.pkcs) {
                delete req.attributes[req.indexOf('pkcs')];
            }
            req.addAttribute(new ldap.Attribute({
                type: 'pkcs',
                vals: [key.toString('pkcs8')]
            }));

            // If fingerprint is a lie though we have big problems
            var fp = key.fingerprint('md5').toString('hex');
            if (!entry.fingerprint || entry.fingerprint.length === 0) {
                req.addAttribute(new ldap.Attribute({
                    type: 'fingerprint',
                    vals: [fp]
                }));
            } else if (fp !== entry.fingerprint[0]) {
                throw new Error('Calculated fingerprint (' + fp + ') for ' +
                    'this key does not match the given one (' +
                    entry.fingerprint + ')');
            }

        } catch (e) {
            return next(new ldap.InvalidAttributeSyntaxError(e.toString()));
        }

        return next();
    }

};
<|endoftext|>


<commit_before>(function() {

    'use strict';

    var util = require('util'),
        path = require('path'),
        slug = require('slug'),
        fs = require('fs'),
        yeoman = require('yeoman-generator'),
        chalk = require('chalk');

    var ScaffoldGenerator = module.exports = function ScaffoldGenerator(args, options) {
        var _this = this;

        yeoman.generators.Base.apply(this, arguments);

        this.on('end', function() {
            this.installDependencies({
                skipInstall: options['skipInstall'],
                callback: function() {
                    var command = _this.spawnCommand('npm', ['install', 'glob']);

                    command.on('exit', function() {
                        _this.log(chalk.cyan(' \n \n All done and no errors! Enjoy! \n \n'));
                    });
                }
            });
        });

        this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
    };

    util.inherits(ScaffoldGenerator, yeoman.generators.Base);

    ScaffoldGenerator.prototype.init = function init() {
        var cb = this.async();

        this.log(chalk.cyan('\t \t  ___           __  __     _    _ '));
        this.log(chalk.cyan('\t \t / __| __ __ _ / _|/ _|___| |__| |'));
        this.log(chalk.cyan('\t \t \\__ \\/ _/ _` |  _|  _/ _ \\ / _` |'));
        this.log(chalk.cyan('\t \t |___/\\__\\__,_|_| |_| \\___/_\\__,_|'));

        this.log('\n');

        this.log(chalk.cyan('\t \t [ Welcome to Scaffold Generator ] \n \n'));
        this.log(chalk.green('I will guide you to generate your best workflow. Come with me... \n \n'));

        cb();
    };

    ScaffoldGenerator.prototype.askFor = function askFor() {
        var cb = this.async(),
            _this = this,
            attempts = {
                name: 0,
                description: 0,
                members: 0
            },
            prompts = [{
                name: 'projectName',
                message: 'What is the name of your project?',
                validate: function(input) {
                    var done = this.async();

                    if (input.trim() === '') {
                        if (attempts.name === 0) {
                            attempts.name = 1;
                            done('Hey dude! You forgot to enter the project name!');
                        } else if (attempts.name === 1) {
                            attempts.name = 2;

                            done('Come on. Just write the name of the project.');
                        } else if (attempts.name === 2) {
                            attempts.name = 3;

                            done('Alright. No problem. I\'ll wait here.');
                        } else if (attempts.name === 3) {
                            attempts.name = 4;

                            done('Come on buddy! Write that name. NOW!');
                        } else {
                            done('Ok! :(');
                        }

                        return;
                    }

                    done(true);
                }
            }, {
                name: 'projectDescription',
                message: 'What is the description?',
                validate: function(input) {
                    var done = this.async();

                    if (input.trim() === '') {
                        if (attempts.name > 0) {
                            done('You also forgot the description.');
                        } else {
                            if (attempts.description === 0) {
                                attempts.description = 1;

                                done('You forgot the description. Write here.');
                            } else if (attempts.description === 1) {
                                done('You forgot the description again! Just write.');
                            }
                        }

                        return;
                    }

                    done(true);
                }
            }, {
                name: 'projectMember',
                message: 'What are people going to work on this project? (Separated by commas)',
                validate: function(input) {
                    var done = this.async();

                    if (input.trim() === '') {
                        if (attempts.name > 0 && attempts.description > 0) {
                            done('Forgot again? :/ Who will work with you on this? Write separating the names with commas.');
                        } else {
                            if (attempts.members === 0) {
                                attempts.members = 1;

                                done('Hey man. Who will work with you on this? Write separating the names with commas.');
                            } else if (attempts.members === 1) {
                                done('Type the name of who will work with you, separated by commas.');
                            }
                        }

                        return;
                    }

                    done(true);
                }
            }, {
                type: 'list',
                name: 'projectType',
                message: 'What kind of project?',
                choices: ['Mobile Only', 'Web Only', 'Responsive'],
                default: 0
            }, {
                type: 'confirm',
                name: 'jquery',
                message: 'Want to include jQuery?',
                default: 0
            }];

        this.prompt(prompts, function(props) {
            for(var item in props) {
                this[item] = props[item];
            }

            this.log(chalk.red(' \n \n Good! Now I will download everything you need. Time to take a coffee! \n \n'));

            cb();
        }.bind(this));
    };

    ScaffoldGenerator.prototype.getScaffoldCore = function getScaffoldCore() {
        var cb = this.async();

        this.log(chalk.green('\n \n Downloading core of scaffold'));
        this.tarball('https://github.com/marcosmoura/scaffold/archive/v2.zip', '.', cb);
    };

    ScaffoldGenerator.prototype.processPackage = function processPackage() {
        var cb = this.async(),
            pkgPath = path.join(this.env.cwd, 'package.json'),
            pkg = JSON.parse(this.readFileAsString(pkgPath));

        pkg.projectName = this.projectName;
        pkg.name = slug(this.projectName.toLowerCase());
        pkg.description = this.projectDescription;
        pkg.developers = this.projectMember;

        var dev = this.projectMember.split(','),
            devList = [];

        for(var member in dev) {
            devList.push({
                'name': dev[member].trim()
            });
        }

        pkg.author = devList;

        fs.unlink(pkgPath);

        this.write(pkgPath, JSON.stringify(pkg, null, 2));

        cb();
    };

    ScaffoldGenerator.prototype.processBower = function processBower() {
        var cb = this.async(),
            bowerJson = path.join(this.env.cwd, 'bower.json'),
            bower = JSON.parse(this.readFileAsString(bowerJson));

        if (this.projectType === 'Web Only') {
            delete bower.dependencies.fastclick;
        }

        if (!this.jquery) {
            delete bower.dependencies.jquery;
        }

        fs.unlink(bowerJson);

        this.write(bowerJson, JSON.stringify(bower, null, 2));

        cb();
    };

    ScaffoldGenerator.prototype.getScaffoldVersion = function getScaffoldVersion() {
        var cb = this.async();

        if (this.projectType === 'Mobile Only') {
            this.log(chalk.green('\n \n Downloading mobile version'));
            this.tarball('https://github.com/marcosmoura/scaffold-mobile/archive/master.zip', 'dev/', cb);
        } else if (this.projectType === 'Web Only') {
            this.log(chalk.green('\n \n Downloading web version'));
            this.tarball('https://github.com/marcosmoura/scaffold-web/archive/master.zip', 'dev/', cb);
        } else if (this.projectType === 'Responsive') {
            this.log(chalk.green('\n \n Downloading responsive version'));
            this.tarball('https://github.com/marcosmoura/scaffold-responsive/archive/master.zip', 'dev/', cb);
        }
    };

    ScaffoldGenerator.prototype.garbageRemoval = function garbageRemoval() {
        var cb = this.async(),
            devPath = path.join(this.env.cwd, 'dev');

        this.log(chalk.red('\n \n Removing garbage and temporary files'));

        fs.unlink(path.join(devPath, 'LICENSE'));
        fs.unlink(path.join(devPath, 'README.md'));

        this.log(chalk.green('\n \n Now I will install the dependencies. This may take a while. Time to go to the bathroom! \n \n '));

        cb();
    };

})();
<commit_msg>Improves legibility<commit_after>(function() {

    'use strict';

    var util = require('util'),
        path = require('path'),
        slug = require('slug'),
        fs = require('fs'),
        yeoman = require('yeoman-generator'),
        chalk = require('chalk');

    var ScaffoldGenerator = module.exports = function ScaffoldGenerator(args, options) {
        var _this = this;

        yeoman.generators.Base.apply(this, arguments);

        this.on('end', function() {
            this.installDependencies({
                skipInstall: options['skipInstall'],
                callback: function() {
                    var command = _this.spawnCommand('npm', ['install', 'glob']);

                    command.on('exit', function() {
                        _this.log(chalk.cyan(' \n \n All done and no errors! Enjoy! \n \n'));
                    });
                }
            });
        });

        this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
    };

    util.inherits(ScaffoldGenerator, yeoman.generators.Base);

    ScaffoldGenerator.prototype.init = function init() {
        var cb = this.async();

        this.log(chalk.cyan('\t \t  ___           __  __     _    _ '));
        this.log(chalk.cyan('\t \t / __| __ __ _ / _|/ _|___| |__| |'));
        this.log(chalk.cyan('\t \t \\__ \\/ _/ _` |  _|  _/ _ \\ / _` |'));
        this.log(chalk.cyan('\t \t |___/\\__\\__,_|_| |_| \\___/_\\__,_|'));

        this.log('\n');

        this.log(chalk.cyan('\t \t [ Welcome to Scaffold Generator ] \n \n'));
        this.log(chalk.green('I will guide you to generate your best workflow. Come with me... \n \n'));

        cb();
    };

    ScaffoldGenerator.prototype.askFor = function askFor() {
        var cb = this.async(),
            _this = this,
            attempts = {
                name: 0,
                description: 0,
                members: 0
            },
            prompts = [{
                name: 'projectName',
                message: 'What is the name of your project?',
                validate: function(input) {
                    var done = this.async();

                    if (input.trim() === '') {
                        if (attempts.name === 0) {
                            attempts.name = 1;
                            done('Hey dude! You forgot to enter the project name!');
                        } else if (attempts.name === 1) {
                            attempts.name = 2;

                            done('Come on. Just write the name of the project.');
                        } else if (attempts.name === 2) {
                            attempts.name = 3;

                            done('Alright. No problem. I\'ll wait here.');
                        } else if (attempts.name === 3) {
                            attempts.name = 4;

                            done('Come on buddy! Write that name. NOW!');
                        } else {
                            done('Ok! :(');
                        }

                        return;
                    }

                    done(true);
                }
            }, {
                name: 'projectDescription',
                message: 'What is the description?',
                validate: function(input) {
                    var done = this.async();

                    if (input.trim() === '') {
                        if (attempts.name > 0) {
                            done('You also forgot the description.');
                        } else {
                            if (attempts.description === 0) {
                                attempts.description = 1;

                                done('You forgot the description. Write here.');
                            } else if (attempts.description === 1) {
                                done('You forgot the description again! Just write.');
                            }
                        }

                        return;
                    }

                    done(true);
                }
            }, {
                name: 'projectMember',
                message: 'What are people going to work on this project? (Separated by commas)',
                validate: function(input) {
                    var done = this.async();

                    if (input.trim() === '') {
                        if (attempts.name > 0 && attempts.description > 0) {
                            done('Forgot again? :/ Who will work with you on this? Write separating the names with commas.');
                        } else {
                            if (attempts.members === 0) {
                                attempts.members = 1;

                                done('Hey man. Who will work with you on this? Write separating the names with commas.');
                            } else if (attempts.members === 1) {
                                done('Type the name of who will work with you, separated by commas.');
                            }
                        }

                        return;
                    }

                    done(true);
                }
            }, {
                type: 'list',
                name: 'projectType',
                message: 'What kind of project?',
                choices: ['Mobile Only', 'Web Only', 'Responsive'],
                default: 0
            }, {
                type: 'confirm',
                name: 'jquery',
                message: 'Want to include jQuery?',
                default: 0
            }];

        this.prompt(prompts, function(props) {
            for(var item in props) {
                this[item] = props[item];
            }

            this.log(chalk.yellow(' \n \n Good! Now I will download everything you need. Time to take a coffee! \n \n'));

            cb();
        }.bind(this));
    };

    ScaffoldGenerator.prototype.getScaffoldCore = function getScaffoldCore() {
        var cb = this.async();

        this.log(chalk.green('\n \n Downloading core of scaffold'));
        this.tarball('https://github.com/marcosmoura/scaffold/archive/v2.zip', '.', cb);
    };

    ScaffoldGenerator.prototype.processPackage = function processPackage() {
        var cb = this.async(),
            pkgPath = path.join(this.env.cwd, 'package.json'),
            pkg = JSON.parse(this.readFileAsString(pkgPath));

        pkg.projectName = this.projectName;
        pkg.name = slug(this.projectName.toLowerCase());
        pkg.description = this.projectDescription;
        pkg.developers = this.projectMember;

        var dev = this.projectMember.split(','),
            devList = [];

        for(var member in dev) {
            devList.push({
                'name': dev[member].trim()
            });
        }

        pkg.author = devList;

        fs.unlink(pkgPath);

        this.write(pkgPath, JSON.stringify(pkg, null, 2));

        cb();
    };

    ScaffoldGenerator.prototype.processBower = function processBower() {
        var cb = this.async(),
            bowerJson = path.join(this.env.cwd, 'bower.json'),
            bower = JSON.parse(this.readFileAsString(bowerJson));

        if (this.projectType === 'Web Only') {
            delete bower.dependencies.fastclick;
        }

        if (!this.jquery) {
            delete bower.dependencies.jquery;
        }

        fs.unlink(bowerJson);

        this.write(bowerJson, JSON.stringify(bower, null, 2));

        cb();
    };

    ScaffoldGenerator.prototype.getScaffoldVersion = function getScaffoldVersion() {
        var cb = this.async();

        if (this.projectType === 'Mobile Only') {
            this.log(chalk.green('\n \n Downloading mobile version'));
            this.tarball('https://github.com/marcosmoura/scaffold-mobile/archive/master.zip', 'dev/', cb);
        } else if (this.projectType === 'Web Only') {
            this.log(chalk.green('\n \n Downloading web version'));
            this.tarball('https://github.com/marcosmoura/scaffold-web/archive/master.zip', 'dev/', cb);
        } else if (this.projectType === 'Responsive') {
            this.log(chalk.green('\n \n Downloading responsive version'));
            this.tarball('https://github.com/marcosmoura/scaffold-responsive/archive/master.zip', 'dev/', cb);
        }
    };

    ScaffoldGenerator.prototype.garbageRemoval = function garbageRemoval() {
        var cb = this.async(),
            devPath = path.join(this.env.cwd, 'dev');

        this.log(chalk.yellow('\n \n Removing garbage and temporary files'));

        fs.unlink(path.join(devPath, 'LICENSE'));
        fs.unlink(path.join(devPath, 'README.md'));

        this.log(chalk.green('\n \n Now I will install the dependencies. This may take a while. Time to go to the bathroom! \n \n '));

        cb();
    };

})();
<|endoftext|>


<commit_before>var queue = require('queue-async');
var events = require('events');
var util = require('util');
var URL = require('url');
var qs = require('querystring');
var typeis = require('type-is').is;
var bufferEqual = require('buffer-equal');
var agent = require('./utils/agent');
var debug = require('debug')('raja:core');

module.exports = function(opts, cb) {
	var raja = new Raja(opts);
	raja.error = Raja.prototype.error.bind(raja);
	raja.agent = agent;

	raja.proxies = {};
	raja.builders = {};

	raja.proxies.local = require('./proxies/local')(raja, opts);
	raja.proxies.remote = require('./proxies/remote')(raja, opts);
	raja.proxies.express = require('./proxies/express')(raja, opts);
	raja.proxies.statics = opts.statics && require('./proxies/statics')(raja, opts);

	raja.init(function(err) {
		raja.proxies.dom = opts.dom && require('./proxies/dom')(raja, opts);
		cb(err, raja);
	});
	return raja;
};

module.exports.agent = agent;

function Raja(opts) {
	this.opts = opts || {};
	if (!this.opts.namespace) {
		this.opts.namespace = "";
		console.info("Raja expects a namespace, using empty string");
	}
	this.unsaved = {};
}
util.inherits(Raja, events.EventEmitter);

Raja.prototype.init = function(cb) {
	queue(2)
	.defer(require('./io'), this, this.opts)
	.defer(require('./store'), this, this.opts)
	.await(function(err, io, store) {
		if (err) return cb(err);
		if (this.opts.client && !io) return cb(new Error("raja failed to init io"));
		if (!store) return cb(new Error("raja failed to init store"));
		this.io = io;
		this.store = store;
		this.session = require('./store/session').bind(null, this);
		this.emit('ready');
		cb(null, this);
	}.bind(this));
};

// internal function
Raja.prototype.receive = function(msg) {
	debug('receive', msg);
	if (!msg.key) return;
	if (!msg.parents) msg.parents = [];
	if (msg.mtime) msg.mtime = new Date(msg.mtime);
	this.emit('message', msg);
	this.store.invalidateParents(msg, function(err) {
		if (err) console.error(err);
	});
};

Raja.prototype.send = function(msg) {
	if (!msg.key) {
		return this.error(new Error("Missing key in " + JSON.stringify(msg)));
	}
	if (!msg.mtime) msg.mtime = Date.now();
	else if (msg.mtime instanceof Date) msg.mtime = msg.mtime.getTime();
	if (this.io) this.io.send(msg);
};

Raja.prototype.error = function(err) {
	// called when an error happened while using raja
	if (err) console.error(err);
};

Raja.prototype.shallow = shallow;

Raja.prototype.dataEqual = dataEqual;

Raja.prototype.create = function(obj, from) {
	if (typeof obj == "string") obj = {url: obj};
	if (from) {
		obj.headers = this.headers(from);
		if (from.builder) obj.builder = from.builder;
	}
	if (!obj.url) {
		if (from && from.url) {
			obj.url = from.url;
		} else if (obj.key) {
			obj.url = keyObj(obj.key).url;
		} else {
			throw new Error("Missing key in " + JSON.stringify(obj));
		}
	}
	obj.key = this.reskey(obj);
	var inst = this.unsaved[obj.key];
	if (!inst) {
		inst = Object.create(Resource.prototype, {});
		this.shallow(obj, inst);
		debug('create unsaved', inst.key);
		Object.defineProperty(inst, 'raja', {
			enumerable: false,
			value: this
		});
		this.unsaved[inst.key] = inst;
	} else {
		debug('update unsaved', obj.key);
		this.shallow(obj, inst);
	}
	return inst;
};

Raja.prototype.reskey = function(obj, havingHeaders) {
	if (typeof obj == "string") obj = {
		url: obj
	};
	if (!obj.headers && havingHeaders) obj.headers = this.headers(havingHeaders);
	var xRaja = obj.headers && obj.headers['X-Raja'];
	var url = obj.url;
	if (xRaja == this.opts.namespace) {
		url = URL.parse(url).path;
	}
	return this.key(url, this.vary(obj.headers));
};

Raja.prototype.reqkey = function(obj, havingHeaders) {
	if (typeof obj == "string") obj = {
		url: obj
	};
	if (!obj.headers && havingHeaders) obj.headers = this.headers(havingHeaders);
	var xRaja = obj.headers && obj.headers['X-Raja'];
	var url = obj.url;
	if (xRaja == this.opts.namespace) {
		url = URL.parse(url).path;
	}
	return this.key(url, this.variant(obj.headers));
};

Raja.prototype.retrieve = function(url, havingHeaders, cb) {
	if (!cb && typeof havingHeaders == "function") {
		cb = havingHeaders;
		havingHeaders = null;
	}
	var key = this.reskey(url, havingHeaders);
	this.store.get(key, cb);
};

Raja.prototype.upsert = function(obj, cb) {
	debug('upsert', obj);
	this.retrieve(obj.url, obj, function(err, resource) {
		if (err) return cb(err);
		if (!resource) {
			debug('upsert not found, creating');
			resource = this.create(obj);
		} else {
			debug('upsert found, updating', resource.key, resource.headers);
			this.shallow(obj, resource);
			resource.headers = this.headers(resource);
		}
		cb(null, resource);
	}.bind(this));
};

function Resource() { /* initialization code will not be called by Object.create */ }

Resource.prototype.depend = function(resource, havingHeaders) {
	if (!this.resources) this.resources = {};
	if (!(resource instanceof Resource)) resource = this.raja.create(resource, havingHeaders);
	if (this.key == resource.key) console.warn('A resource cannot depend on itself', this.key);
	else this.resources[resource.key] = resource;
	debug('depend', this.key, resource.key);
};

Resource.prototype.undepend = function(resource) {
	if (!this.resources || !resource) return;
	var key;
	if (typeof resource == "string") key = resource;
	else key = this.raja.reskey(resource);
	delete this.resources[key];
};

Resource.prototype.belong = function(resource, havingHeaders) {
	if (!this.parents) this.parents = {};
	if (!(resource instanceof Resource)) resource = this.raja.create(resource, havingHeaders);
	if (this.key == resource.key) console.warn('A resource cannot belong to itself', this.key);
	else this.parents[resource.key] = resource;
	debug('belong', this.key, resource.key);
};

Resource.prototype.unbelong = function(resource) {
	if (!this.parents || !resource) return;
	var key;
	if (typeof resource == "string") key = resource;
	else key = this.raja.reskey(resource);
	delete this.parents[key];
};

Resource.prototype.save = function(cb) {
	var raja = this.raja;
	cb = cb || raja.error;
	if (!this.url) {
		if (this.key) {
			this.url = keyObj(this.key).url;
		} else {
			throw new Error("Missing key in " + JSON.stringify(this));
		}
	}
	var key = raja.reskey(this);
	if (this.key == key) {
		raja.store.set(key, this, function(err, resource) {
			delete raja.unsaved[key];
			cb(err, resource);
		});
	} else {
		var oldkey = this.key;
		this.key = key;
		var copy = raja.create(this);
		this.key = oldkey;
		if (this.page) delete this.page;
		this.remove(raja.error);
		if (copy.page && copy.page.unlock) copy.page.unlock = function(copy) {
			debug("call page copy unlock");
			delete copy.page;
		}.bind(this, copy);
		copy.save(cb);
	}
};

Resource.prototype.load = function(remote, opts, cb) {
	if (!this.resources) this.resources = {};
	if (!cb && typeof opts == "function") {
		cb = opts;
		opts = null;
	}
	if (!opts) opts = {};
	remote = agent.resolve(this.url, remote);
	var localns = this.headers && this.headers['X-Raja'];
	var remotens = opts.headers && opts.headers['X-Raja'];
	if (localns && !remotens && URL.parse(this.url).host == URL.parse(remote).host) {
		if (!opts.headers) opts.headers = {};
		opts.headers['X-Raja'] = localns;
	}
	this.raja.proxies.remote.get(remote, opts, function(err, resource) {
		if (err >= 400 && err < 500) {
			this.undepend(resource);
		} else if (!err) {
			this.depend(resource);
		}
		cb(err, resource);
	}.bind(this));
};

Resource.prototype.invalidate = function(cb) {
	this.raja.store.invalidate(this.key, cb);
};

Resource.prototype.is = function(mimetype) {
	return typeis(this.headers && this.headers['Content-Type'], mimetype);
};

Resource.prototype.remove = function(cb) {
	// remove from unsave, from limbo, from store, and orphan everywhere
	delete this.raja.unsaved[this.key];
	this.raja.store.del(this.key, cb);
};

Raja.prototype.headers = function(havingHeaders) {
	if (!havingHeaders) return {};
	var obj = {};
	var headers = havingHeaders.headers;
	var hasGet = !!havingHeaders.get;
	if (!headers && !hasGet) headers = havingHeaders;
	['Content-Type', 'Vary', 'ETag', 'Accept', 'X-Grant', 'X-Right', 'X-Author', 'X-Raja'].forEach(function(name) {
		var val = hasGet && havingHeaders.get(name) || headers && (headers[name] || headers[name.toLowerCase()]);
		if (val) obj[name] = val;
	});
	return obj;
};

Raja.prototype.vary = function(headers) {
	if (!headers) return;
	var vary = {};
	if (!headers.Vary) return vary;
	headers.Vary.split(',').forEach(function(header) {
		header = header.trim();
		var val = headers[header] || "";
		if (!val) return;
		if (header == 'Content-Type') {
			var type = typeis(val, ['html', 'json', 'xml']);
			if (type && type != 'html') vary.type = type; // store html as default
		} else if (header == 'X-Grant') {
			vary.right = normalizeList(val);
		} else if (header == 'X-Author') {
			vary.author = val;
		}
	});
	return vary;
};

Raja.prototype.variant = function(headers) {
	if (!headers) return;
	var variant = {};
	var accept = headers['Accept'] || "";
	if (accept) {
		// html is considered the default type
		var type = typeis(accept, ['html', 'json', 'xml']);
		if (type && type != 'html') variant.type = type;
	}
	var right = headers['X-Right'] || "";
	if (right) {
		variant.right = normalizeList(right);
	}
	var author = headers['X-Author'];
	if (author) {
		variant.author = author;
	}
	return variant;
};

Raja.prototype.key = function(url, obj) {
	if (!obj) return url;
	for (var k in obj) if (obj[k] == null) delete obj[k];
	var str = obj && qs.stringify(obj);
	if (str) url = str + ' ' + url;
	return url;
};

Raja.prototype.keyObj = keyObj;

function shallow(src, dst) {
	dst = dst || {};
	if (!src) return dst;
	Object.keys(src).forEach(function(key) {
		if (src.hasOwnProperty(key) == false) return;
		var val = src[key];
		if (val === undefined) return;
		if (key == "resources" || key == "parents" || key == "headers") {
			val = shallow(val, dst[key] || {});
		}
		if ((key == 'resources' || key == 'parents') && val && Object.keys(val).length == 0 && dst[key] && Object.keys(dst[key]).length > 0) {
			console.info("not overwriting", key, dst[key], "with empty object");
			return;
		}
		dst[key] = val;
	});
	return dst;
}

function keyObj(key) {
	if (!key) return {};
	var obj;
	var find = /^(.*\s)?((?:https?:\/\/|\/).+)$/.exec(key);
	if (find != null && find.length == 3) {
		var query = find[1];
		if (query) {
			obj = qs.parse(query);
		} else {
			obj = {};
		}
		obj.url = find[2];
	} else {
		obj = {url: key};
	}
	return obj;
}

function normalizeList(strlist) {
	return strlist.split(',').map(function(str) {return str.trim();}).sort().join(',');
}

function dataEqual(a, b) {
	if (a == null || b == null) return a === b;
	var bufa = Buffer.isBuffer(a);
	var bufb = Buffer.isBuffer(b);
	if (!bufa && !bufb) return a === b;
	if (!bufa) a = new Buffer(a);
	if (!bufb) b = new Buffer(b);
	return bufferEqual(a, b);
}

<commit_msg>Calls to depend/belong with url and no req/res imply same namespace<commit_after>var queue = require('queue-async');
var events = require('events');
var util = require('util');
var URL = require('url');
var qs = require('querystring');
var typeis = require('type-is').is;
var bufferEqual = require('buffer-equal');
var agent = require('./utils/agent');
var debug = require('debug')('raja:core');

module.exports = function(opts, cb) {
	var raja = new Raja(opts);
	raja.error = Raja.prototype.error.bind(raja);
	raja.agent = agent;

	raja.proxies = {};
	raja.builders = {};

	raja.proxies.local = require('./proxies/local')(raja, opts);
	raja.proxies.remote = require('./proxies/remote')(raja, opts);
	raja.proxies.express = require('./proxies/express')(raja, opts);
	raja.proxies.statics = opts.statics && require('./proxies/statics')(raja, opts);

	raja.init(function(err) {
		raja.proxies.dom = opts.dom && require('./proxies/dom')(raja, opts);
		cb(err, raja);
	});
	return raja;
};

module.exports.agent = agent;

function Raja(opts) {
	this.opts = opts || {};
	if (!this.opts.namespace) {
		this.opts.namespace = "";
		console.info("Raja expects a namespace, using empty string");
	}
	this.unsaved = {};
}
util.inherits(Raja, events.EventEmitter);

Raja.prototype.init = function(cb) {
	queue(2)
	.defer(require('./io'), this, this.opts)
	.defer(require('./store'), this, this.opts)
	.await(function(err, io, store) {
		if (err) return cb(err);
		if (this.opts.client && !io) return cb(new Error("raja failed to init io"));
		if (!store) return cb(new Error("raja failed to init store"));
		this.io = io;
		this.store = store;
		this.session = require('./store/session').bind(null, this);
		this.emit('ready');
		cb(null, this);
	}.bind(this));
};

// internal function
Raja.prototype.receive = function(msg) {
	debug('receive', msg);
	if (!msg.key) return;
	if (!msg.parents) msg.parents = [];
	if (msg.mtime) msg.mtime = new Date(msg.mtime);
	this.emit('message', msg);
	this.store.invalidateParents(msg, function(err) {
		if (err) console.error(err);
	});
};

Raja.prototype.send = function(msg) {
	if (!msg.key) {
		return this.error(new Error("Missing key in " + JSON.stringify(msg)));
	}
	if (!msg.mtime) msg.mtime = Date.now();
	else if (msg.mtime instanceof Date) msg.mtime = msg.mtime.getTime();
	if (this.io) this.io.send(msg);
};

Raja.prototype.error = function(err) {
	// called when an error happened while using raja
	if (err) console.error(err);
};

Raja.prototype.shallow = shallow;

Raja.prototype.dataEqual = dataEqual;

Raja.prototype.create = function(obj, from) {
	if (typeof obj == "string") obj = {url: obj};
	if (from) {
		obj.headers = this.headers(from);
		if (from.builder) obj.builder = from.builder;
	}
	if (!obj.url) {
		if (from && from.url) {
			obj.url = from.url;
		} else if (obj.key) {
			obj.url = keyObj(obj.key).url;
		} else {
			throw new Error("Missing key in " + JSON.stringify(obj));
		}
	}
	obj.key = this.reskey(obj);
	var inst = this.unsaved[obj.key];
	if (!inst) {
		inst = Object.create(Resource.prototype, {});
		this.shallow(obj, inst);
		debug('create unsaved', inst.key);
		Object.defineProperty(inst, 'raja', {
			enumerable: false,
			value: this
		});
		this.unsaved[inst.key] = inst;
	} else {
		debug('update unsaved', obj.key);
		this.shallow(obj, inst);
	}
	return inst;
};

Raja.prototype.reskey = function(obj, havingHeaders) {
	if (typeof obj == "string") obj = {
		url: obj
	};
	if (!obj.headers && havingHeaders) obj.headers = this.headers(havingHeaders);
	var xRaja = obj.headers && obj.headers['X-Raja'];
	var url = obj.url;
	if (xRaja == this.opts.namespace) {
		url = URL.parse(url).path;
	}
	return this.key(url, this.vary(obj.headers));
};

Raja.prototype.reqkey = function(obj, havingHeaders) {
	if (typeof obj == "string") obj = {
		url: obj
	};
	if (!obj.headers && havingHeaders) obj.headers = this.headers(havingHeaders);
	var xRaja = obj.headers && obj.headers['X-Raja'];
	var url = obj.url;
	if (xRaja == this.opts.namespace) {
		url = URL.parse(url).path;
	}
	return this.key(url, this.variant(obj.headers));
};

Raja.prototype.retrieve = function(url, havingHeaders, cb) {
	if (!cb && typeof havingHeaders == "function") {
		cb = havingHeaders;
		havingHeaders = null;
	}
	var key = this.reskey(url, havingHeaders);
	this.store.get(key, cb);
};

Raja.prototype.upsert = function(obj, cb) {
	debug('upsert', obj);
	this.retrieve(obj.url, obj, function(err, resource) {
		if (err) return cb(err);
		if (!resource) {
			debug('upsert not found, creating');
			resource = this.create(obj);
		} else {
			debug('upsert found, updating', resource.key, resource.headers);
			this.shallow(obj, resource);
			resource.headers = this.headers(resource);
		}
		cb(null, resource);
	}.bind(this));
};

function Resource() { /* initialization code will not be called by Object.create */ }

Resource.prototype.depend = function(resource, havingHeaders) {
	if (!this.resources) this.resources = {};
	if (!(resource instanceof Resource)) {
		if (!havingHeaders) havingHeaders = {
			'X-Raja': this.raja.opts.namespace
		};
		resource = this.raja.create(resource, havingHeaders);
	}
	if (this.key == resource.key) console.warn('A resource cannot depend on itself', this.key);
	else this.resources[resource.key] = resource;
	debug('depend', this.key, resource.key);
};

Resource.prototype.undepend = function(resource) {
	if (!this.resources || !resource) return;
	var key;
	if (typeof resource == "string") key = resource;
	else key = this.raja.reskey(resource);
	delete this.resources[key];
};

Resource.prototype.belong = function(resource, havingHeaders) {
	if (!this.parents) this.parents = {};
	if (!(resource instanceof Resource)) {
		resource = this.raja.create(resource, havingHeaders);
		if (!havingHeaders) havingHeaders = {
			'X-Raja': this.raja.opts.namespace
		};
	}
	if (this.key == resource.key) console.warn('A resource cannot belong to itself', this.key);
	else this.parents[resource.key] = resource;
	debug('belong', this.key, resource.key);
};

Resource.prototype.unbelong = function(resource) {
	if (!this.parents || !resource) return;
	var key;
	if (typeof resource == "string") key = resource;
	else key = this.raja.reskey(resource);
	delete this.parents[key];
};

Resource.prototype.save = function(cb) {
	var raja = this.raja;
	cb = cb || raja.error;
	if (!this.url) {
		if (this.key) {
			this.url = keyObj(this.key).url;
		} else {
			throw new Error("Missing key in " + JSON.stringify(this));
		}
	}
	var key = raja.reskey(this);
	if (this.key == key) {
		raja.store.set(key, this, function(err, resource) {
			delete raja.unsaved[key];
			cb(err, resource);
		});
	} else {
		var oldkey = this.key;
		this.key = key;
		var copy = raja.create(this);
		this.key = oldkey;
		if (this.page) delete this.page;
		this.remove(raja.error);
		if (copy.page && copy.page.unlock) copy.page.unlock = function(copy) {
			debug("call page copy unlock");
			delete copy.page;
		}.bind(this, copy);
		copy.save(cb);
	}
};

Resource.prototype.load = function(remote, opts, cb) {
	if (!this.resources) this.resources = {};
	if (!cb && typeof opts == "function") {
		cb = opts;
		opts = null;
	}
	if (!opts) opts = {};
	remote = agent.resolve(this.url, remote);
	var localns = this.headers && this.headers['X-Raja'];
	var remotens = opts.headers && opts.headers['X-Raja'];
	if (localns && !remotens && URL.parse(this.url).host == URL.parse(remote).host) {
		if (!opts.headers) opts.headers = {};
		opts.headers['X-Raja'] = localns;
	}
	this.raja.proxies.remote.get(remote, opts, function(err, resource) {
		if (err >= 400 && err < 500) {
			this.undepend(resource);
		} else if (!err) {
			this.depend(resource);
		}
		cb(err, resource);
	}.bind(this));
};

Resource.prototype.invalidate = function(cb) {
	this.raja.store.invalidate(this.key, cb);
};

Resource.prototype.is = function(mimetype) {
	return typeis(this.headers && this.headers['Content-Type'], mimetype);
};

Resource.prototype.remove = function(cb) {
	// remove from unsave, from limbo, from store, and orphan everywhere
	delete this.raja.unsaved[this.key];
	this.raja.store.del(this.key, cb);
};

Raja.prototype.headers = function(havingHeaders) {
	if (!havingHeaders) return {};
	var obj = {};
	var headers = havingHeaders.headers;
	var hasGet = !!havingHeaders.get;
	if (!headers && !hasGet) headers = havingHeaders;
	['Content-Type', 'Vary', 'ETag', 'Accept', 'X-Grant', 'X-Right', 'X-Author', 'X-Raja'].forEach(function(name) {
		var val = hasGet && havingHeaders.get(name) || headers && (headers[name] || headers[name.toLowerCase()]);
		if (val) obj[name] = val;
	});
	return obj;
};

Raja.prototype.vary = function(headers) {
	if (!headers) return;
	var vary = {};
	if (!headers.Vary) return vary;
	headers.Vary.split(',').forEach(function(header) {
		header = header.trim();
		var val = headers[header] || "";
		if (!val) return;
		if (header == 'Content-Type') {
			var type = typeis(val, ['html', 'json', 'xml']);
			if (type && type != 'html') vary.type = type; // store html as default
		} else if (header == 'X-Grant') {
			vary.right = normalizeList(val);
		} else if (header == 'X-Author') {
			vary.author = val;
		}
	});
	return vary;
};

Raja.prototype.variant = function(headers) {
	if (!headers) return;
	var variant = {};
	var accept = headers['Accept'] || "";
	if (accept) {
		// html is considered the default type
		var type = typeis(accept, ['html', 'json', 'xml']);
		if (type && type != 'html') variant.type = type;
	}
	var right = headers['X-Right'] || "";
	if (right) {
		variant.right = normalizeList(right);
	}
	var author = headers['X-Author'];
	if (author) {
		variant.author = author;
	}
	return variant;
};

Raja.prototype.key = function(url, obj) {
	if (!obj) return url;
	for (var k in obj) if (obj[k] == null) delete obj[k];
	var str = obj && qs.stringify(obj);
	if (str) url = str + ' ' + url;
	return url;
};

Raja.prototype.keyObj = keyObj;

function shallow(src, dst) {
	dst = dst || {};
	if (!src) return dst;
	Object.keys(src).forEach(function(key) {
		if (src.hasOwnProperty(key) == false) return;
		var val = src[key];
		if (val === undefined) return;
		if (key == "resources" || key == "parents" || key == "headers") {
			val = shallow(val, dst[key] || {});
		}
		if ((key == 'resources' || key == 'parents') && val && Object.keys(val).length == 0 && dst[key] && Object.keys(dst[key]).length > 0) {
			console.info("not overwriting", key, dst[key], "with empty object");
			return;
		}
		dst[key] = val;
	});
	return dst;
}

function keyObj(key) {
	if (!key) return {};
	var obj;
	var find = /^(.*\s)?((?:https?:\/\/|\/).+)$/.exec(key);
	if (find != null && find.length == 3) {
		var query = find[1];
		if (query) {
			obj = qs.parse(query);
		} else {
			obj = {};
		}
		obj.url = find[2];
	} else {
		obj = {url: key};
	}
	return obj;
}

function normalizeList(strlist) {
	return strlist.split(',').map(function(str) {return str.trim();}).sort().join(',');
}

function dataEqual(a, b) {
	if (a == null || b == null) return a === b;
	var bufa = Buffer.isBuffer(a);
	var bufb = Buffer.isBuffer(b);
	if (!bufa && !bufb) return a === b;
	if (!bufa) a = new Buffer(a);
	if (!bufb) b = new Buffer(b);
	return bufferEqual(a, b);
}

<|endoftext|>


<commit_before>// New Relic Server monitoring support
if ( process.env.NEW_RELIC_ENABLED ) {
  require( "newrelic" );
}

const restify = require('restify');
const applyRoutes = require('./routes');
const logger = require('./lib/logger')
const middleware = require('./lib/middleware')
const package = require('../package')

const server = restify.createServer({
  name: 'openbadger',
  version: package.version,
  log: logger,
});

server.pre(restify.pre.sanitizePath());
server.use(restify.acceptParser(server.acceptable));
server.use(restify.queryParser({mapParams: false}));
server.use(restify.bodyParser({mapParams: false, rejectUnknown: true}));
server.use(middleware.verifyRequest())
server.use(middleware.attachResolvePath())
server.use(middleware.attachErrorLogger())

applyRoutes(server);

module.exports = server;

if (!module.parent) {
  server.listen(process.env.PORT || 8080, function () {
    console.log('%s listening at %s', server.name, server.url);
  });
}
<commit_msg>Use `package.name` in the app definition.<commit_after>// New Relic Server monitoring support
if ( process.env.NEW_RELIC_ENABLED ) {
  require( "newrelic" );
}

const restify = require('restify');
const applyRoutes = require('./routes');
const logger = require('./lib/logger')
const middleware = require('./lib/middleware')
const package = require('../package')

const server = restify.createServer({
  name: package.name,
  version: package.version,
  log: logger,
});

server.pre(restify.pre.sanitizePath());
server.use(restify.acceptParser(server.acceptable));
server.use(restify.queryParser({mapParams: false}));
server.use(restify.bodyParser({mapParams: false, rejectUnknown: true}));
server.use(middleware.verifyRequest())
server.use(middleware.attachResolvePath())
server.use(middleware.attachErrorLogger())

applyRoutes(server);

module.exports = server;

if (!module.parent) {
  server.listen(process.env.PORT || 8080, function () {
    console.log('%s listening at %s', server.name, server.url);
  });
}
<|endoftext|>


<commit_before>/*
How to create a battle scene.
Scene(createBattleScene([
  [`avenger`, [0, 0, 0]],
  [`child`, [1, 0, -1]],
  [`protector`, [-1, 1, 0]],
  [`persecutor`, [-1, 0, 1]],
],5));
*/

import { add } from 'pura/vector/tuple';
import { camera, } from 'camera';
import { uiElements } from 'ui';
import Song from 'audio';
import battleMusic from 'songs/summer';
import finalBossMusic from 'songs/winter';
import Menu from 'menu';
import StatusBar from 'battle/statusBar';
import BattleMap from 'battle/map';
import { initializeMap, turnOrder, moveCharacter } from 'battle/grid';
import Move from 'battle/actions/Move';
import Swarm from 'battle/actions/Swarm';
import state from 'state';

const cameraOffset = [0, -150];

function* generateGetCharacter(turnOrder) {
  let i = 0;
  while(true) {
    const char = turnOrder[i % (turnOrder.length)];
    ++i;
    const [, health] = char;
    if(health > 0) {
      yield char;
    }
  }
}

export default function createBattleScene(characters, mapSize) {
  initializeMap(characters, mapSize);

  let turn = null;
  let selectedAction = null;
  const action = {
    // Player Controlled Character Movement
    move: (character) => [`Move`, () => selectedAction = Move(character)],
    swarm: (character) => [`Swarm`, () => selectedAction = Swarm(character)],
    // Player Controlled Attack
    // attack: (character, { name, range, damage }) => ([name, () => selectedAction = function* () {
    //   const [, , position] = character;
    //   // 1) Detect & Display possible attackers
    //   clear(optionHexes);
    //   const nearbyTargets = getNearbyEnemies(position, range);
    //   optionHexes.push(...nearbyTargets);
    //   // 1b) If none display warning text ( there are no nearby enemies) and prompt a reselection
    //   if(!nearbyTargets.length) {
    //     // TODO: SOMETHING HERE
    //   }
    //   // 2) Wait for player to select target.
    //   let selectedTarget = null;
    //   while(!selectedTarget) {
    //     cameraControls();
    //     const { click, mousePosition } = inputs;
    //     if(click === 1) {
    //       state.target = getGridHexFromVector2d(
    //         scaleSet(calcWorldPosition(mousePosition), 1 / gridScale)
    //       );
    //       if(contains(optionHexes, state.target)) selectedTarget = getCharacterAtHex(state.target);
    //     }
    //     yield;
    //   }
    //   clear(optionHexes);
    //   // 3) Inflict damage on target
    //   selectedTarget[1] += damage;
    //   // 4) Play animation
    //   // const attackAnimation = animation(character, selectedTarget);
    //   // while(!attackAnimation()) yield;
    // }()]),
    // defense: (character, { name, range, percentage, duration }) => ([name, () => selectedAction = function* () {
    //   // 1) Detect & display all eligible characters
    //   const [, , position] = character;
    //   // 1) Detect & Display possible attackers
    //   clear(optionHexes);
    //   const nearbyTargets = getNearbyAllies(position, range);
    //   optionHexes.push(...nearbyTargets);
    //   // 2) Wait for confirmation
    //   let confirmed = false;
    //   const confirmMenuIndex = uiElements.push(Menu([
    //     [`Confirm`, () => confirmed = true],
    //     [`Cancel`, () => { }],
    //   ]));
    //   while(confirmed) {
    //     cameraControls();
    //     yield;
    //   }
    //   uiElements.splice(confirmMenuIndex, 1);
    //   // 3) Add status effect
    //   nearbyTargets
    //     .map(getCharacterAtHex)
    //     .filter(x => x)
    //     .forEach(([, , , status]) => status.push({
    //       type: `shield`,
    //       duration,
    //       percentage,
    //     }));
    //   // 4) Play animation
    // }()]),
    // magic: (character, { name, range, effect }) => ([name, () => selectedAction = (function* () {
    //   const [data, , position] = character;
    //   // 1) Detect & display all eligible characters
    //   clear(optionHexes);
    //   const nearbyTargets = [getNearbyAllies(position, range), getNearbyEnemies(position, range)];
    //   optionHexes.push(...nearbyTargets);
    //   // 2) Select Target
    //   let selectedTarget = null;
    //   while(!selectedTarget) {
    //     cameraControls();
    //     const { click, mousePosition } = inputs;
    //     if(click === 1) {
    //       state.target = getGridHexFromVector2d(
    //         scaleSet(calcWorldPosition(mousePosition), 1 / gridScale)
    //       );
    //       if(contains(optionHexes, state.target)) selectedTarget = getCharacterAtHex(state.target);
    //     }
    //     yield;
    //   }
    //   clear(optionHexes);
    //   // 3) confirm (maybe?)
    //   // Will comeback to this is this seems necessary
    //   // 4) Add status effect
    //   const [tData, , , tStatus] = selectedTarget;
    //   tStatus.push({
    //     name: data.alignment === tData.alignment
    //       ? `hot`
    //       : `dot`,
    //     effect,
    //   });
    //   // 5) Play animation
    // })()]),
  };

  const getCharacter = generateGetCharacter(turnOrder);
  function* Turn() {
    // 1) Determine who's turn it is.
    const { value: character } = getCharacter.next();
    const [data, , position] = character;
    console.log(`------------------------------`);
    console.log(`Start of turn for ${data.name}`);
    // 2) Center Camera on that person.
    const panCamera = moveCharacter(camera, add(cameraOffset, position), 2000);
    console.log(`Paning Camera from ${camera} to ${add(cameraOffset, position)}`);
    while(!panCamera()) yield;
    // 3) Look up actions
    const actions = Object.keys(data.abilities).map(name => action[name](character, data.abilities[name]));
    // 4) Add actions to the menu
    const menuUIIndex = uiElements.push(Menu(actions));
    // 5) Wait for player to select an action.
    selectedAction = null;
    while(!selectedAction) yield;
    uiElements.splice(menuUIIndex - 1, 1);
    // 6) Execute selected action
    while(true) {
      const { done } = selectedAction.next();
      if(done) break;
      else yield;
    }
    // 7) Check to see if battle is over
    const isVictory = false;//!!turnOrder.find(([data, health]) => !data.alignment && health > 0);
    const isDefeat = false;//!isVictory && !!turnOrder.find(([data, health]) => data.alignment && health > 0);
    console.log(`------------------------------`);
    return isVictory ? 1 :
      isDefeat ? 2 :
        0;
  }

  const bgMusic = new Song(battleMusic || finalBossMusic);

  return {
    init: () => {
      bgMusic.play(bgMusic);
      camera[2] = 340;
      uiElements.push(StatusBar, BattleMap);
      turn = Turn();
      state.logic = () => {
        // done: is turn over.
        // value: battle status, 0: ongoing, 1: victory, 2: defeat;
        const { value, done } = turn.next();
        if(done && value === 0) {
          // 8) Increment turn counter
          // 9A) Create New turn
          turn = Turn();
        } else if(done && value === 1) {
          // 9B) VICTORY
        } else if(done && value === 2) {
          // 9C) DEFEAT
        }
      };
    },
    dismiss: () => {
      bgMusic.stop();
    },
  };
}
<commit_msg>Fix battle<commit_after>/*
How to create a battle scene.
Scene(createBattleScene([
  [`avenger`, [0, 0, 0]],
  [`child`, [1, 0, -1]],
  [`protector`, [-1, 1, 0]],
  [`persecutor`, [-1, 0, 1]],
],5));
*/

import { add } from 'pura/vector/tuple';
import { camera, } from 'camera';
import { uiElements } from 'ui';
import Song from 'audio';
import battleMusic from 'songs/summer';
import finalBossMusic from 'songs/winter';
import Menu from 'menu';
import StatusBar from 'battle/statusBar';
import BattleMap from 'battle/map';
import { initializeMap, turnOrder, moveCharacter } from 'battle/grid';
import Move from 'battle/actions/Move';
import Attack from 'battle/actions/Attack';
import Swarm from 'battle/actions/Swarm';
import state from 'state';

const cameraOffset = [0, -150];

function* generateGetCharacter(turnOrder) {
  let i = 0;
  while(true) {
    const char = turnOrder[i % (turnOrder.length)];
    ++i;
    const [, health] = char;
    if(health > 0) {
      yield char;
    }
  }
}

export default function createBattleScene(characters, mapSize) {
  initializeMap(characters, mapSize);

  let turn = null;
  let selectedAction = null;
  const action = {
    // Player Controlled Character Movement
    move: (character) => [`Move`, () => selectedAction = Move(character)],
    attack: (character) => [character[0].abilities.attack.name, () => selectedAction = Attack(character)],
    swarm: (character) => [`Swarm`, () => selectedAction = Swarm(character)],
    // defense: (character, { name, range, percentage, duration }) => ([name, () => selectedAction = function* () {
    //   // 1) Detect & display all eligible characters
    //   const [, , position] = character;
    //   // 1) Detect & Display possible attackers
    //   clear(optionHexes);
    //   const nearbyTargets = getNearbyAllies(position, range);
    //   optionHexes.push(...nearbyTargets);
    //   // 2) Wait for confirmation
    //   let confirmed = false;
    //   const confirmMenuIndex = uiElements.push(Menu([
    //     [`Confirm`, () => confirmed = true],
    //     [`Cancel`, () => { }],
    //   ]));
    //   while(confirmed) {
    //     cameraControls();
    //     yield;
    //   }
    //   uiElements.splice(confirmMenuIndex, 1);
    //   // 3) Add status effect
    //   nearbyTargets
    //     .map(getCharacterAtHex)
    //     .filter(x => x)
    //     .forEach(([, , , status]) => status.push({
    //       type: `shield`,
    //       duration,
    //       percentage,
    //     }));
    //   // 4) Play animation
    // }()]),
    // magic: (character, { name, range, effect }) => ([name, () => selectedAction = (function* () {
    //   const [data, , position] = character;
    //   // 1) Detect & display all eligible characters
    //   clear(optionHexes);
    //   const nearbyTargets = [getNearbyAllies(position, range), getNearbyEnemies(position, range)];
    //   optionHexes.push(...nearbyTargets);
    //   // 2) Select Target
    //   let selectedTarget = null;
    //   while(!selectedTarget) {
    //     cameraControls();
    //     const { click, mousePosition } = inputs;
    //     if(click === 1) {
    //       state.target = getGridHexFromVector2d(
    //         scaleSet(calcWorldPosition(mousePosition), 1 / gridScale)
    //       );
    //       if(contains(optionHexes, state.target)) selectedTarget = getCharacterAtHex(state.target);
    //     }
    //     yield;
    //   }
    //   clear(optionHexes);
    //   // 3) confirm (maybe?)
    //   // Will comeback to this is this seems necessary
    //   // 4) Add status effect
    //   const [tData, , , tStatus] = selectedTarget;
    //   tStatus.push({
    //     name: data.alignment === tData.alignment
    //       ? `hot`
    //       : `dot`,
    //     effect,
    //   });
    //   // 5) Play animation
    // })()]),
  };

  const getCharacter = generateGetCharacter(turnOrder);
  function* Turn() {
    // 1) Determine who's turn it is.
    const { value: character } = getCharacter.next();
    const [data, , position] = character;
    console.log(`------------------------------`);
    console.log(`Start of turn for ${data.name}`);
    // 2) Center Camera on that person.
    const panCamera = moveCharacter(camera, add(cameraOffset, position), 2000);
    console.log(`Paning Camera from ${camera} to ${add(cameraOffset, position)}`);
    while(!panCamera()) yield;
    // 3) Look up actions
    const actions = Object.keys(data.abilities).map(name => action[name](character, data.abilities[name]));
    // 4) Add actions to the menu
    const menuUIIndex = uiElements.push(Menu(actions));
    // 5) Wait for player to select an action.
    selectedAction = null;
    while(!selectedAction) yield;
    uiElements.splice(menuUIIndex - 1, 1);
    // 6) Execute selected action
    while(true) {
      const { done } = selectedAction.next();
      if(done) break;
      else yield;
    }
    // 7) Check to see if battle is over
    const isVictory = false;//!!turnOrder.find(([data, health]) => !data.alignment && health > 0);
    const isDefeat = false;//!isVictory && !!turnOrder.find(([data, health]) => data.alignment && health > 0);
    console.log(`------------------------------`);
    return isVictory ? 1 :
      isDefeat ? 2 :
        0;
  }

  const bgMusic = new Song(battleMusic || finalBossMusic);

  return {
    init: () => {
      bgMusic.play(bgMusic);
      camera[2] = 340;
      uiElements.push(BattleMap, StatusBar);
      turn = Turn();
      state.logic = () => {
        // done: is turn over.
        // value: battle status, 0: ongoing, 1: victory, 2: defeat;
        const { value, done } = turn.next();
        if(done && value === 0) {
          // 8) Increment turn counter
          // 9A) Create New turn
          turn = Turn();
        } else if(done && value === 1) {
          // 9B) VICTORY
        } else if(done && value === 2) {
          // 9C) DEFEAT
        }
      };
    },
    dismiss: () => {
      bgMusic.stop();
    },
  };
}
<|endoftext|>