<commit_before>#import "assertions.js"
#import "lang-ext.js"

extend(UIATableView.prototype, {
  /**
   * A shortcut for:
   *  this.cells().firstWithName(name)
   */
  cellNamed: function(name) {
    return this.cells().firstWithName(name);
  },

  /**
   * Asserts that this table has a cell with the name (accessibility label)
   * matching the given +name+ argument.
   */
  assertCellNamed: function(name) {
    assertNotNull(this.cellNamed(name), "No table cell found named '" + name + "'");
  }
});

extend(UIAElement.prototype, {
	// Poll till the item becomes visible, up to a specified timeout
	waitForVisible: function (timeout, step)
	{
	        if (step == null)
	        {
	                step = 0.5;
	        }

	        var stop = timeout/step;

	        for (var i = 0; i < stop; i++)
	        {
	                UIATarget.localTarget().delay(step); // for the animation
	                if (this.isVisible())
	                {
	                        return;
	                }
	        }
	        this.logElement();
	        throw("Not visible");
	},

	/**
   * A shortcut for waiting an element to become visible and tap.
   */
  vtap: function() {
    this.waitForVisible(10, 0.25);
    this.tap();
  },
  /**
   * A shortcut for touching an element and waiting for it to disappear.
   */
  tapAndWaitForInvalid: function() {
    this.tap();
    this.waitForInvalid();
  }
});

extend(UIAApplication.prototype, {
  /**
   * A shortcut for getting the current view controller's title from the
   * navigation bar. If there is no navigation bar, this method returns null
   */
  navigationTitle: function() {
    navBar = this.mainWindow().navigationBar();
    if (navBar) {
      return navBar.name();
    }
    return null;
  },

  /**
   * A shortcut for checking that the interface orientation in either
   * portrait mode
   */
   isPortraitOrientation: function() {
     var orientation = this.interfaceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_PORTRAIT ||
       orientation == UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN;
   },

  /**
   * A shortcut for checking that the interface orientation in one of the
   * landscape orientations.
   */
   isLandscapeOrientation: function() {
     var orientation = this.interfaceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_LANDSCAPELEFT ||
       orientation == UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT;
   }
});

extend(UIANavigationBar.prototype, {
  /**
   * Asserts that the left button's name matches the given +name+ argument
   */
  assertLeftButtonNamed: function(name) {
    assertEquals(name, this.leftButton().name());
  },

  /**
   * Asserts that the right button's name matches the given +name+ argument
   */
  assertRightButtonNamed: function(name) {
    assertEquals(name, this.rightButton().name());
  }
});

extend(UIATarget.prototype, {
  /**
   * A shortcut for checking that the interface orientation in either
   * portrait mode
   */
   isPortraitOrientation: function() {
     var orientation = this.deviceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_PORTRAIT ||
       orientation == UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN;
   },

  /**
   * A shortcut for checking that the interface orientation in one of the
   * landscape orientations.
   */
   isLandscapeOrientation: function() {
     var orientation = this.deviceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_LANDSCAPELEFT ||
       orientation == UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT;
   },

   /**
    * A convenience method for detecting that you're running on an iPad
    */
    isDeviceiPad: function() {
      return this.model().match(/^iPad/) !== null;
    },

    /**
     * A convenience method for detecting that you're running on an
     * iPhone or iPod touch
     */
    isDeviceiPhone: function() {
      return this.model().match(/^iPhone/) !== null;
    }
});
extend(UIAKeyboard.prototype,{
	KEYBOARD_TYPE_UNKNOWN :-1,
	KEYBOARD_TYPE_ALPHA : 0,
	KEYBOARD_TYPE_ALPHA_CAPS : 1,
	KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION:2,
	KEYBOARD_TYPE_NUMBER:3,
	keyboardType : function()
	    {
			if (this.keys().length < 12){
	            return this.KEYBOARD_TYPE_NUMBER;
			}
	        else if (this.keys().firstWithName("a").toString() != "[object UIAElementNil]")
	            return this.KEYBOARD_TYPE_ALPHA;
	        else if (this.keys().firstWithName("A").toString() != "[object UIAElementNil]")
	            return this.KEYBOARD_TYPE_ALPHA_CAPS;
	        else if (this.keys().firstWithName("1").toString() != "[object UIAElementNil]")
	            return this.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION;
	        else
	            return this.KEYBOARD_TYPE_UNKNOWN;
	    }

});

/*
TODO: Character keyboard is super slow.
*/
var typeString = function(pstrString, pbClear)
{
    if (!this.hasKeyboardFocus())
        this.tap();

    UIATarget.localTarget().delay(0.5);

    if (pbClear || pstrString.length == 0)
        this.clear();

    if (pstrString.length > 0)
    {
        var app = UIATarget.localTarget().frontMostApp();
        var keyboard = app.keyboard();
        var keys = app.keyboard().keys();
        var buttons = app.keyboard().buttons();
        for (i = 0; i < pstrString.length; i++)
        {
	        var intKeyboardType = keyboard.keyboardType();
	        var bIsAllCaps = (intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA_CAPS); //Handles autocapitalizationType = UITextAutocapitalizationTypeAllCharacters
	        var intNewKeyboardType = intKeyboardType;
            var strChar = pstrString.charAt(i);
            if ((/[a-z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA_CAPS && !bIsAllCaps)
            {
                buttons.firstWithName("shift").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_ALPHA;
            }
            else if ((/[A-Z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA)
            {
                buttons.firstWithName("shift").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_ALPHA_CAPS;
            }
            else if ((/[A-z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION)
            {
                buttons.firstWithName("more, letters").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_ALPHA;
            }
            else if ((/[0-9.]/.test(strChar)) && intKeyboardType != keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION && intKeyboardType != keyboard.KEYBOARD_TYPE_NUMBER)
            {
                buttons.firstWithName("more, numbers").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION;
            }

            if ((/[a-z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA_CAPS)
                strChar = strChar.toUpperCase();
            if (strChar == " ")
                keys["space"].tap();
            else if (/[0-9]/.test(strChar)) // Need to change strChar to the index key of the number because strChar = "0" will tap "1" and strChar = "1" will tap "2"
            {
               	if (strChar == "0")
					if (intKeyboardType == keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION){
                    	strChar = "9";
					}
					else{
						strChar = "10";
					}
               	else
                   	strChar = (parseInt(strChar) - 1).toString();

                keys[strChar].tap();
            }
            else{
                keys[strChar].tap(); // TODO: this line is super slow when there are many keys
			}
            UIATarget.localTarget().delay(0.5);

        }
    }
};

extend(UIATextField.prototype,{
	typeString: typeString,
});
extend(UIATextView.prototype,{
	typeString: typeString
});<commit_msg>Added support to pass in number in typeString method<commit_after>#import "assertions.js"
#import "lang-ext.js"

extend(UIATableView.prototype, {
  /**
   * A shortcut for:
   *  this.cells().firstWithName(name)
   */
  cellNamed: function(name) {
    return this.cells().firstWithName(name);
  },

  /**
   * Asserts that this table has a cell with the name (accessibility label)
   * matching the given +name+ argument.
   */
  assertCellNamed: function(name) {
    assertNotNull(this.cellNamed(name), "No table cell found named '" + name + "'");
  }
});

extend(UIAElement.prototype, {
	// Poll till the item becomes visible, up to a specified timeout
	waitForVisible: function (timeout, step)
	{
	        if (step == null)
	        {
	                step = 0.5;
	        }

	        var stop = timeout/step;

	        for (var i = 0; i < stop; i++)
	        {
	                UIATarget.localTarget().delay(step); // for the animation
	                if (this.isVisible())
	                {
	                        return;
	                }
	        }
	        this.logElement();
	        throw("Not visible");
	},

	/**
   * A shortcut for waiting an element to become visible and tap.
   */
  vtap: function() {
    this.waitForVisible(10, 0.25);
    this.tap();
  },
  /**
   * A shortcut for touching an element and waiting for it to disappear.
   */
  tapAndWaitForInvalid: function() {
    this.tap();
    this.waitForInvalid();
  }
});

extend(UIAApplication.prototype, {
  /**
   * A shortcut for getting the current view controller's title from the
   * navigation bar. If there is no navigation bar, this method returns null
   */
  navigationTitle: function() {
    navBar = this.mainWindow().navigationBar();
    if (navBar) {
      return navBar.name();
    }
    return null;
  },

  /**
   * A shortcut for checking that the interface orientation in either
   * portrait mode
   */
   isPortraitOrientation: function() {
     var orientation = this.interfaceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_PORTRAIT ||
       orientation == UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN;
   },

  /**
   * A shortcut for checking that the interface orientation in one of the
   * landscape orientations.
   */
   isLandscapeOrientation: function() {
     var orientation = this.interfaceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_LANDSCAPELEFT ||
       orientation == UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT;
   }
});

extend(UIANavigationBar.prototype, {
  /**
   * Asserts that the left button's name matches the given +name+ argument
   */
  assertLeftButtonNamed: function(name) {
    assertEquals(name, this.leftButton().name());
  },

  /**
   * Asserts that the right button's name matches the given +name+ argument
   */
  assertRightButtonNamed: function(name) {
    assertEquals(name, this.rightButton().name());
  }
});

extend(UIATarget.prototype, {
  /**
   * A shortcut for checking that the interface orientation in either
   * portrait mode
   */
   isPortraitOrientation: function() {
     var orientation = this.deviceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_PORTRAIT ||
       orientation == UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN;
   },

  /**
   * A shortcut for checking that the interface orientation in one of the
   * landscape orientations.
   */
   isLandscapeOrientation: function() {
     var orientation = this.deviceOrientation();
     return orientation == UIA_DEVICE_ORIENTATION_LANDSCAPELEFT ||
       orientation == UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT;
   },

   /**
    * A convenience method for detecting that you're running on an iPad
    */
    isDeviceiPad: function() {
      return this.model().match(/^iPad/) !== null;
    },

    /**
     * A convenience method for detecting that you're running on an
     * iPhone or iPod touch
     */
    isDeviceiPhone: function() {
      return this.model().match(/^iPhone/) !== null;
    }
});
extend(UIAKeyboard.prototype,{
	KEYBOARD_TYPE_UNKNOWN :-1,
	KEYBOARD_TYPE_ALPHA : 0,
	KEYBOARD_TYPE_ALPHA_CAPS : 1,
	KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION:2,
	KEYBOARD_TYPE_NUMBER:3,
	keyboardType : function()
	    {
			if (this.keys().length < 12){
	            return this.KEYBOARD_TYPE_NUMBER;
			}
	        else if (this.keys().firstWithName("a").toString() != "[object UIAElementNil]")
	            return this.KEYBOARD_TYPE_ALPHA;
	        else if (this.keys().firstWithName("A").toString() != "[object UIAElementNil]")
	            return this.KEYBOARD_TYPE_ALPHA_CAPS;
	        else if (this.keys().firstWithName("1").toString() != "[object UIAElementNil]")
	            return this.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION;
	        else
	            return this.KEYBOARD_TYPE_UNKNOWN;
	    }

});

/*
TODO: Character keyboard is super slow.
*/
var typeString = function(pstrString, pbClear)
{
	pstrString += ''; // convert number to string

	if (!this.hasKeyboardFocus())
        this.tap();

    UIATarget.localTarget().delay(0.5);

    if (pbClear || pstrString.length == 0)
        this.clear();

    if (pstrString.length > 0)
    {
        var app = UIATarget.localTarget().frontMostApp();
        var keyboard = app.keyboard();
        var keys = app.keyboard().keys();
        var buttons = app.keyboard().buttons();
        for (i = 0; i < pstrString.length; i++)
        {
	        var intKeyboardType = keyboard.keyboardType();
	        var bIsAllCaps = (intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA_CAPS); //Handles autocapitalizationType = UITextAutocapitalizationTypeAllCharacters
	        var intNewKeyboardType = intKeyboardType;
            var strChar = pstrString.charAt(i);
            if ((/[a-z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA_CAPS && !bIsAllCaps)
            {
                buttons.firstWithName("shift").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_ALPHA;
            }
            else if ((/[A-Z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA)
            {
                buttons.firstWithName("shift").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_ALPHA_CAPS;
            }
            else if ((/[A-z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION)
            {
                buttons.firstWithName("more, letters").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_ALPHA;
            }
            else if ((/[0-9.]/.test(strChar)) && intKeyboardType != keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION && intKeyboardType != keyboard.KEYBOARD_TYPE_NUMBER)
            {
                buttons.firstWithName("more, numbers").tap();
                intKeyboardType = keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION;
            }

            if ((/[a-z]/.test(strChar)) && intKeyboardType == keyboard.KEYBOARD_TYPE_ALPHA_CAPS)
                strChar = strChar.toUpperCase();
            if (strChar == " ")
                keys["space"].tap();
            else if (/[0-9]/.test(strChar)) // Need to change strChar to the index key of the number because strChar = "0" will tap "1" and strChar = "1" will tap "2"
            {
               	if (strChar == "0")
					if (intKeyboardType == keyboard.KEYBOARD_TYPE_NUMBER_AND_PUNCTUATION){
                    	strChar = "9";
					}
					else{
						strChar = "10";
					}
               	else
                   	strChar = (parseInt(strChar) - 1).toString();

                keys[strChar].tap();
            }
            else{
                keys[strChar].tap(); // TODO: this line is super slow when there are many keys
			}
            UIATarget.localTarget().delay(0.5);

        }
    }
};

extend(UIATextField.prototype,{
	typeString: typeString,
});
extend(UIATextView.prototype,{
	typeString: typeString
});<|endoftext|>


<commit_before>/**
 * Lo-Dash 2.2.1 (Custom Build) <http://lodash.com/>
 * Build: `lodash modularize underscore exports="node" -o ./underscore/`
 * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
 * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
 * Available under MIT license <http://lodash.com/license>
 */
var arrays = require('./arrays'),
    chaining = require('./chaining'),
    collections = require('./collections'),
    functions = require('./functions'),
    objects = require('./objects'),
    utilities = require('./utilities'),
    forEach = require('./collections/forEach'),
    forOwn = require('./objects/forOwn'),
    lodashWrapper = require('./internals/lodashWrapper'),
    mixin = require('./utilities/mixin'),
    support = require('./support');

/**
 * Used for `Array` method references.
 *
 * Normally `Array.prototype` would suffice, however, using an array literal
 * avoids issues in Narwhal.
 */
var arrayRef = [];

/**
 * Creates a `lodash` object which wraps the given value to enable intuitive
 * method chaining.
 *
 * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
 * and `unshift`
 *
 * Chaining is supported in custom builds as long as the `value` method is
 * implicitly or explicitly included in the build.
 *
 * The chainable wrapper functions are:
 * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
 * `compose`, `concat`, `countBy`, `createCallback`, `curry`, `debounce`,
 * `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`,
 * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`,
 * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`,
 * `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`,
 * `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, `range`, `reject`,
 * `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
 * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
 * `unzip`, `values`, `where`, `without`, `wrap`, and `zip`
 *
 * The non-chainable wrapper functions are:
 * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
 * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
 * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
 * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
 * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
 * `template`, `unescape`, `uniqueId`, and `value`
 *
 * The wrapper functions `first` and `last` return wrapped values when `n` is
 * provided, otherwise they return unwrapped values.
 *
 * Explicit chaining can be enabled by using the `_.chain` method.
 *
 * @name _
 * @constructor
 * @category Chaining
 * @param {*} value The value to wrap in a `lodash` instance.
 * @returns {Object} Returns a `lodash` instance.
 * @example
 *
 * var wrapped = _([1, 2, 3]);
 *
 * // returns an unwrapped value
 * wrapped.reduce(function(sum, num) {
 *   return sum + num;
 * });
 * // => 6
 *
 * // returns a wrapped value
 * var squares = wrapped.map(function(num) {
 *   return num * num;
 * });
 *
 * _.isArray(squares);
 * // => false
 *
 * _.isArray(squares.value());
 * // => true
 */
function lodash(value) {
  return (value instanceof lodash)
    ? value
    : new lodashWrapper(value);
}
// ensure `new lodashWrapper` is an instance of `lodash`
lodashWrapper.prototype = lodash.prototype;

// wrap `_.mixin` so it works when provided only one argument
mixin = (function(fn) {
  return function(object, source) {
    if (!source) {
      source = object;
      object = lodash;
    }
    return fn(object, source);
  };
}(mixin));

// add functions that return wrapped values when chaining
lodash.after = functions.after;
lodash.at = collections.at;
lodash.bind = functions.bind;
lodash.bindAll = functions.bindAll;
lodash.bindKey = functions.bindKey;
lodash.chain = chaining.chain;
lodash.compact = arrays.compact;
lodash.compose = functions.compose;
lodash.countBy = collections.countBy;
lodash.create = objects.create;
lodash.curry = functions.curry;
lodash.debounce = functions.debounce;
lodash.defaults = objects.defaults;
lodash.defer = functions.defer;
lodash.delay = functions.delay;
lodash.difference = arrays.difference;
lodash.filter = collections.filter;
lodash.flatten = arrays.flatten;
lodash.forEach = forEach;
lodash.forInRight = objects.forInRight;
lodash.forOwnRight = objects.forOwnRight;
lodash.functions = objects.functions;
lodash.groupBy = collections.groupBy;
lodash.indexBy = collections.indexBy;
lodash.initial = arrays.initial;
lodash.intersection = arrays.intersection;
lodash.invert = objects.invert;
lodash.invoke = collections.invoke;
lodash.keys = objects.keys;
lodash.map = collections.map;
lodash.max = collections.max;
lodash.memoize = functions.memoize;
lodash.merge = objects.merge;
lodash.min = collections.min;
lodash.omit = objects.omit;
lodash.once = functions.once;
lodash.pairs = objects.pairs;
lodash.partial = functions.partial;
lodash.partialRight = functions.partialRight;
lodash.pick = objects.pick;
lodash.pluck = collections.pluck;
lodash.pull = arrays.pull;
lodash.range = arrays.range;
lodash.reject = collections.reject;
lodash.remove = arrays.remove;
lodash.rest = arrays.rest;
lodash.shuffle = collections.shuffle;
lodash.sortBy = collections.sortBy;
lodash.tap = chaining.tap;
lodash.throttle = functions.throttle;
lodash.times = utilities.times;
lodash.toArray = collections.toArray;
lodash.transform = objects.transform;
lodash.union = arrays.union;
lodash.uniq = arrays.uniq;
lodash.values = objects.values;
lodash.where = collections.where;
lodash.without = arrays.without;
lodash.wrap = functions.wrap;
lodash.zip = arrays.zip;

// add aliases
lodash.collect = collections.map;
lodash.drop = arrays.rest;
lodash.each = forEach;
lodash.extend = objects.assign;
lodash.methods = objects.functions;
lodash.object = arrays.zipObject;
lodash.select = collections.filter;
lodash.tail = arrays.rest;
lodash.unique = arrays.uniq;

// add functions that return unwrapped values when chaining
lodash.clone = objects.clone;
lodash.cloneDeep = objects.cloneDeep;
lodash.contains = collections.contains;
lodash.escape = utilities.escape;
lodash.every = collections.every;
lodash.find = collections.find;
lodash.findIndex = arrays.findIndex;
lodash.findKey = objects.findKey;
lodash.findLast = collections.findLast;
lodash.findLastIndex = arrays.findLastIndex;
lodash.findLastKey = objects.findLastKey;
lodash.has = objects.has;
lodash.identity = utilities.identity;
lodash.indexOf = arrays.indexOf;
lodash.isArguments = objects.isArguments;
lodash.isArray = objects.isArray;
lodash.isBoolean = objects.isBoolean;
lodash.isDate = objects.isDate;
lodash.isElement = objects.isElement;
lodash.isEmpty = objects.isEmpty;
lodash.isEqual = objects.isEqual;
lodash.isFinite = objects.isFinite;
lodash.isFunction = objects.isFunction;
lodash.isNaN = objects.isNaN;
lodash.isNull = objects.isNull;
lodash.isNumber = objects.isNumber;
lodash.isObject = objects.isObject;
lodash.isRegExp = objects.isRegExp;
lodash.isString = objects.isString;
lodash.isUndefined = objects.isUndefined;
lodash.lastIndexOf = arrays.lastIndexOf;
lodash.mixin = mixin;
lodash.noConflict = utilities.noConflict;
lodash.parseInt = utilities.parseInt;
lodash.random = utilities.random;
lodash.reduce = collections.reduce;
lodash.reduceRight = collections.reduceRight;
lodash.result = utilities.result;
lodash.size = collections.size;
lodash.some = collections.some;
lodash.sortedIndex = arrays.sortedIndex;
lodash.template = utilities.template;
lodash.unescape = utilities.unescape;
lodash.uniqueId = utilities.uniqueId;

// add aliases
lodash.all = collections.every;
lodash.any = collections.some;
lodash.detect = collections.find;
lodash.findWhere = collections.findWhere;
lodash.foldl = collections.reduce;
lodash.foldr = collections.reduceRight;
lodash.include = collections.contains;
lodash.inject = collections.reduce;

// add functions capable of returning wrapped and unwrapped values when chaining
lodash.first = arrays.first;
lodash.last = arrays.last;
lodash.sample = collections.sample;

// add aliases
lodash.take = arrays.first;
lodash.head = arrays.first;

// add functions to `lodash.prototype`
mixin(lodash);

/**
 * The semantic version number.
 *
 * @static
 * @memberOf _
 * @type string
 */
lodash.VERSION = '2.2.1';

// add "Chaining" functions to the wrapper
lodash.prototype.chain = chaining.wrapperChain;
lodash.prototype.value = chaining.wrapperValueOf;

  // add `Array` mutator functions to the wrapper
  forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
    var func = arrayRef[methodName];
    lodash.prototype[methodName] = function() {
      var value = this.__wrapped__;
      func.apply(value, arguments);

      // avoid array-like object bugs with `Array#shift` and `Array#splice`
      // in Firefox < 10 and IE < 9
      if (!support.spliceObjects && value.length === 0) {
        delete value[0];
      }
      return this;
    };
  });

  // add `Array` accessor functions to the wrapper
  forEach(['concat', 'join', 'slice'], function(methodName) {
    var func = arrayRef[methodName];
    lodash.prototype[methodName] = function() {
      var value = this.__wrapped__,
          result = func.apply(value, arguments);

      if (this.__chain__) {
        result = new lodashWrapper(result);
        result.__chain__ = true;
      }
      return result;
    };
  });

lodash.support = support;
(lodash.templateSettings = utilities.templateSettings).imports._ = lodash;
module.exports = lodash;
<commit_msg>Don't expose `_.create` for the `underscore` build.<commit_after>/**
 * Lo-Dash 2.2.1 (Custom Build) <http://lodash.com/>
 * Build: `lodash modularize underscore exports="node" -o ./underscore/`
 * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
 * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
 * Available under MIT license <http://lodash.com/license>
 */
var arrays = require('./arrays'),
    chaining = require('./chaining'),
    collections = require('./collections'),
    functions = require('./functions'),
    objects = require('./objects'),
    utilities = require('./utilities'),
    forEach = require('./collections/forEach'),
    forOwn = require('./objects/forOwn'),
    lodashWrapper = require('./internals/lodashWrapper'),
    mixin = require('./utilities/mixin'),
    support = require('./support');

/**
 * Used for `Array` method references.
 *
 * Normally `Array.prototype` would suffice, however, using an array literal
 * avoids issues in Narwhal.
 */
var arrayRef = [];

/**
 * Creates a `lodash` object which wraps the given value to enable intuitive
 * method chaining.
 *
 * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
 * and `unshift`
 *
 * Chaining is supported in custom builds as long as the `value` method is
 * implicitly or explicitly included in the build.
 *
 * The chainable wrapper functions are:
 * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
 * `compose`, `concat`, `countBy`, `createCallback`, `curry`, `debounce`,
 * `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`,
 * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`,
 * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`,
 * `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`,
 * `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, `range`, `reject`,
 * `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
 * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
 * `unzip`, `values`, `where`, `without`, `wrap`, and `zip`
 *
 * The non-chainable wrapper functions are:
 * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
 * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
 * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
 * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
 * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
 * `template`, `unescape`, `uniqueId`, and `value`
 *
 * The wrapper functions `first` and `last` return wrapped values when `n` is
 * provided, otherwise they return unwrapped values.
 *
 * Explicit chaining can be enabled by using the `_.chain` method.
 *
 * @name _
 * @constructor
 * @category Chaining
 * @param {*} value The value to wrap in a `lodash` instance.
 * @returns {Object} Returns a `lodash` instance.
 * @example
 *
 * var wrapped = _([1, 2, 3]);
 *
 * // returns an unwrapped value
 * wrapped.reduce(function(sum, num) {
 *   return sum + num;
 * });
 * // => 6
 *
 * // returns a wrapped value
 * var squares = wrapped.map(function(num) {
 *   return num * num;
 * });
 *
 * _.isArray(squares);
 * // => false
 *
 * _.isArray(squares.value());
 * // => true
 */
function lodash(value) {
  return (value instanceof lodash)
    ? value
    : new lodashWrapper(value);
}
// ensure `new lodashWrapper` is an instance of `lodash`
lodashWrapper.prototype = lodash.prototype;

// wrap `_.mixin` so it works when provided only one argument
mixin = (function(fn) {
  return function(object, source) {
    if (!source) {
      source = object;
      object = lodash;
    }
    return fn(object, source);
  };
}(mixin));

// add functions that return wrapped values when chaining
lodash.after = functions.after;
lodash.at = collections.at;
lodash.bind = functions.bind;
lodash.bindAll = functions.bindAll;
lodash.bindKey = functions.bindKey;
lodash.chain = chaining.chain;
lodash.compact = arrays.compact;
lodash.compose = functions.compose;
lodash.countBy = collections.countBy;
lodash.curry = functions.curry;
lodash.debounce = functions.debounce;
lodash.defaults = objects.defaults;
lodash.defer = functions.defer;
lodash.delay = functions.delay;
lodash.difference = arrays.difference;
lodash.filter = collections.filter;
lodash.flatten = arrays.flatten;
lodash.forEach = forEach;
lodash.forInRight = objects.forInRight;
lodash.forOwnRight = objects.forOwnRight;
lodash.functions = objects.functions;
lodash.groupBy = collections.groupBy;
lodash.indexBy = collections.indexBy;
lodash.initial = arrays.initial;
lodash.intersection = arrays.intersection;
lodash.invert = objects.invert;
lodash.invoke = collections.invoke;
lodash.keys = objects.keys;
lodash.map = collections.map;
lodash.max = collections.max;
lodash.memoize = functions.memoize;
lodash.merge = objects.merge;
lodash.min = collections.min;
lodash.omit = objects.omit;
lodash.once = functions.once;
lodash.pairs = objects.pairs;
lodash.partial = functions.partial;
lodash.partialRight = functions.partialRight;
lodash.pick = objects.pick;
lodash.pluck = collections.pluck;
lodash.pull = arrays.pull;
lodash.range = arrays.range;
lodash.reject = collections.reject;
lodash.remove = arrays.remove;
lodash.rest = arrays.rest;
lodash.shuffle = collections.shuffle;
lodash.sortBy = collections.sortBy;
lodash.tap = chaining.tap;
lodash.throttle = functions.throttle;
lodash.times = utilities.times;
lodash.toArray = collections.toArray;
lodash.transform = objects.transform;
lodash.union = arrays.union;
lodash.uniq = arrays.uniq;
lodash.values = objects.values;
lodash.where = collections.where;
lodash.without = arrays.without;
lodash.wrap = functions.wrap;
lodash.zip = arrays.zip;

// add aliases
lodash.collect = collections.map;
lodash.drop = arrays.rest;
lodash.each = forEach;
lodash.extend = objects.assign;
lodash.methods = objects.functions;
lodash.object = arrays.zipObject;
lodash.select = collections.filter;
lodash.tail = arrays.rest;
lodash.unique = arrays.uniq;

// add functions that return unwrapped values when chaining
lodash.clone = objects.clone;
lodash.cloneDeep = objects.cloneDeep;
lodash.contains = collections.contains;
lodash.escape = utilities.escape;
lodash.every = collections.every;
lodash.find = collections.find;
lodash.findIndex = arrays.findIndex;
lodash.findKey = objects.findKey;
lodash.findLast = collections.findLast;
lodash.findLastIndex = arrays.findLastIndex;
lodash.findLastKey = objects.findLastKey;
lodash.has = objects.has;
lodash.identity = utilities.identity;
lodash.indexOf = arrays.indexOf;
lodash.isArguments = objects.isArguments;
lodash.isArray = objects.isArray;
lodash.isBoolean = objects.isBoolean;
lodash.isDate = objects.isDate;
lodash.isElement = objects.isElement;
lodash.isEmpty = objects.isEmpty;
lodash.isEqual = objects.isEqual;
lodash.isFinite = objects.isFinite;
lodash.isFunction = objects.isFunction;
lodash.isNaN = objects.isNaN;
lodash.isNull = objects.isNull;
lodash.isNumber = objects.isNumber;
lodash.isObject = objects.isObject;
lodash.isRegExp = objects.isRegExp;
lodash.isString = objects.isString;
lodash.isUndefined = objects.isUndefined;
lodash.lastIndexOf = arrays.lastIndexOf;
lodash.mixin = mixin;
lodash.noConflict = utilities.noConflict;
lodash.parseInt = utilities.parseInt;
lodash.random = utilities.random;
lodash.reduce = collections.reduce;
lodash.reduceRight = collections.reduceRight;
lodash.result = utilities.result;
lodash.size = collections.size;
lodash.some = collections.some;
lodash.sortedIndex = arrays.sortedIndex;
lodash.template = utilities.template;
lodash.unescape = utilities.unescape;
lodash.uniqueId = utilities.uniqueId;

// add aliases
lodash.all = collections.every;
lodash.any = collections.some;
lodash.detect = collections.find;
lodash.findWhere = collections.findWhere;
lodash.foldl = collections.reduce;
lodash.foldr = collections.reduceRight;
lodash.include = collections.contains;
lodash.inject = collections.reduce;

// add functions capable of returning wrapped and unwrapped values when chaining
lodash.first = arrays.first;
lodash.last = arrays.last;
lodash.sample = collections.sample;

// add aliases
lodash.take = arrays.first;
lodash.head = arrays.first;

// add functions to `lodash.prototype`
mixin(lodash);

/**
 * The semantic version number.
 *
 * @static
 * @memberOf _
 * @type string
 */
lodash.VERSION = '2.2.1';

// add "Chaining" functions to the wrapper
lodash.prototype.chain = chaining.wrapperChain;
lodash.prototype.value = chaining.wrapperValueOf;

  // add `Array` mutator functions to the wrapper
  forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
    var func = arrayRef[methodName];
    lodash.prototype[methodName] = function() {
      var value = this.__wrapped__;
      func.apply(value, arguments);

      // avoid array-like object bugs with `Array#shift` and `Array#splice`
      // in Firefox < 10 and IE < 9
      if (!support.spliceObjects && value.length === 0) {
        delete value[0];
      }
      return this;
    };
  });

  // add `Array` accessor functions to the wrapper
  forEach(['concat', 'join', 'slice'], function(methodName) {
    var func = arrayRef[methodName];
    lodash.prototype[methodName] = function() {
      var value = this.__wrapped__,
          result = func.apply(value, arguments);

      if (this.__chain__) {
        result = new lodashWrapper(result);
        result.__chain__ = true;
      }
      return result;
    };
  });

lodash.support = support;
(lodash.templateSettings = utilities.templateSettings).imports._ = lodash;
module.exports = lodash;
<|endoftext|>


<commit_before>var argp = require ("./lib");
var utils = require ("utils");

//All operations are synchronous

//argp.debug it's true if the node process is started in debug mode:
//node debug <script> ...

var opts = argp
		.on ("argument", function (argument){
			//argument is a string
			console.log (argument);
			console.log (argp.arguments ()); //Returns an array with all the defined arguments
			//fail() prints a message to stderr and exits. Messages are prefixed like so:
			//<script>: message...
			if (argument === "fail") argp.fail ("fail() test");
		})
		.on ("option", function (option, value){
			//option is a string
			//value is undefined if the option is a flag or the value returned by the
			//replacer; it can be null if is optional
			console.log (option);
			utils.inspect (argp.options (), { depth: null }); //Returns an array with all the defined options
		})
		.on ("end", function (){
			//Called when all the options and arguments are parsed, just before parse returns
			//This is the place to clean up and prepare information
			console.log ("end");
		})
		.configure ({
			//false: options are parsed first, then the arguments
			//true: options and arguments are parsed in the same order they come
			//Options and arguments can override each other if they have the same name
			inOrder: false, //Default is false
			columns: 80, //Default is 80
			//No error with duplicate options
			undefinedArguments: true, //Allows to write any argument
			undefinedOptions: false, //Does not allow to write undefined options
			//-h, --help and --usage are default options
			//Short and long names can be changed:
			//var arr = argp.options ()
			//arr[arr.length - 2].short = "?"; //help option
			//arr[arr.length - 1].short = "u"; //usage option
			showHelp: true, //Default is true
			showUsage: true //Default is true
		})
		//Adds the option -v, --version
		.version ("v0.0.1") //Typically: .version("v" + require("package.json").version)
		//By default, the usage description is:
		//<filename> [OPTIONS...]
		//followed by all the defined arguments surrounded by []:
		//<filename> [OPTIONS...] [arg1] [arg2]
		//With the usage() function it can be changed and add multiple uses:
		//Usage: my-script hack nasa
		//       my-script goto jail
		.usage ("my-script hack nasa")
		.usage ("my-script goto jail")
		.description ("Show some dots on the screen.")
		//Defined arguments
		//Argument definitions can be configured at any time, they don't need to be
		//set before the options
		.argument ("build")
		.argument ("fail")
		//Options and group definitions have an insertion order
		//Options can be grouped
		.group ("Basic options") //Internally it creates a numeric id
		//Defined options
		.option ({
			long: "dot",
			short: "d",
			string: "NUM", //If the string is null it's a flag and "reviver", "value"
										 //and "optional" are ignored and "negate" can be configured
										 //Default is null so all the options are flags by default
										 //Example of flags:
										 //.option({ short: "f1", description: "..." })
										 //.option({ short: "f2", long: "flag2", negate: true }) -> --no-flag2
			description: "Show NUM dots on the screen.", //Default is null
			value: 1, //Default value, default is null
			optional: false, //Default is false
			hidden: false, //Default is false
			reviver: function (value){
				//Transforms the value
				//Useful to parse comma-separated values, dates, etc
				//Default is null
				return value;
			}
		})
		//This group applies to --help, --usage and --version
		.group ("Informational options")
		//Footer information
		.footer ("Bye!")
		//Only one call to parse is allowed, subsequent calls throw an error
		.parse ();

//At this point all the data is ready to be used
//opts.dot
//opts.build
//opts.fail
utils.inspect (opts, { depth: null });<commit_msg>comments<commit_after>var argp = require ("./lib");
var utils = require ("utils");

//All operations are synchronous

//argp.debug it's true if the node process is started in debug mode:
//node debug <script> ...

var opts = argp
		//With the obj parameter we can define "alias", for example a flag "-f" that
		//the same as "-a 3". When the flag "-f" is found it can just do: "obj.a = 3"
		.on ("argument", function (obj, argument){
			//obj is the final object with al the options/arguments already parsed
			//argument is a string
			console.log (argument);
			console.log (argp.arguments ()); //Returns an array with all the defined arguments
			//fail() prints a message to stderr and exits. Messages are prefixed like so:
			//<script>: message...
			if (argument === "fail") argp.fail ("fail() test");
		})
		.on ("option", function (obj, option, value){
			//obj is the final object with al the options/arguments already parsed
			//option is a string
			//value is undefined if the option is a flag or the value returned by the
			//replacer; it can be null if is optional
			console.log (option);
			utils.inspect (argp.options (), { depth: null }); //Returns an array with all the defined options
		})
		.on ("end", function (){
			//Called when all the options and arguments are parsed, just before parse returns
			//This is the place to clean up and prepare information
			console.log ("end");
		})
		.configure ({
			//false: options are parsed first, then the arguments
			//true: options and arguments are parsed in the same order they come
			//Options and arguments can override each other if they have the same name
			inOrder: false, //Default is false
			columns: 80, //Default is 80
			//No error with duplicate options
			undefinedArguments: true, //Allows to write any argument
			undefinedOptions: false, //Does not allow to write undefined options
			//-h, --help and --usage are default options
			//Short and long names can be changed:
			//var arr = argp.options ()
			//arr[arr.length - 2].short = "?"; //help option
			//arr[arr.length - 1].short = "u"; //usage option
			showHelp: true, //Default is true
			showUsage: true //Default is true
		})
		//Adds the option -v, --version
		.version ("v0.0.1") //Typically: .version("v" + require("package.json").version)
		//By default, the usage description is:
		//<filename> [OPTIONS...]
		//followed by all the defined arguments surrounded by []:
		//<filename> [OPTIONS...] [arg1] [arg2]
		//With the usage() function it can be changed and add multiple uses:
		//Usage: my-script hack nasa
		//       my-script goto jail
		.usage ("my-script hack nasa")
		.usage ("my-script goto jail")
		.description ("Show some dots on the screen.")
		//Defined arguments
		//Argument definitions can be configured at any time, they don't need to be
		//set before the options
		.argument ("build")
		.argument ("fail")
		//Options and group definitions have an insertion order
		//Options can be grouped
		.group ("Basic options") //Internally it creates a numeric id
		//Defined options
		.option ({
			//If long and short are defined, the long name is used to save the value in the final object
			long: "dot",
			short: "d",
			string: "NUM", //If the string is null it's a flag and "reviver", "value"
										 //and "optional" are ignored and "negate" can be configured
										 //Default is null so all the options are flags by default
										 //Example of flags:
										 //.option({ short: "f1", description: "..." })
										 //.option({ short: "f2", long: "flag2", negate: true }) -> --no-flag2
			description: "Show NUM dots on the screen.", //Default is null
			value: 1, //Default value, default is null
			optional: false, //Default is false
			hidden: false, //Default is false
			reviver: function (value){
				//Transforms the value
				//Useful to parse comma-separated values, dates, etc
				//Default is null
				return value;
			}
		})
		//This group applies to --help, --usage and --version
		.group ("Informational options")
		//Footer information
		.footer ("Bye!")
		//Only one call to parse is allowed, subsequent calls throw an error
		.parse ();

//At this point all the data is ready to be used
//opts.dot
//opts.build
//opts.fail
utils.inspect (opts, { depth: null });<|endoftext|>


<commit_before>(function(window, document, undefined){
	/*jshint eqnull:true */
	'use strict';

	if(!document.addEventListener){return;}

	var config, riasCfg;
	var replaceTypes = {string: 1, number: 1};
	var regNumber = /^\-*\+*\d+\.*\d*$/;
	var regPicture = /^picture$/i;
	var regWidth = /\s*\{\s*width\s*\}\s*/i;
	var regPlaceholder = /\s*\{\s*([a-z0-9]+)\s*\}\s*/ig;
	var regObj = /^\[.*\]|\{.*\}$/;
	var regAllowedSizes = /^(?:auto|\d+(px)?)$/;
	var anchor = document.createElement('a');
	var img = document.createElement('img');
	var buggySizes = ('srcset' in img) && !('sizes' in img);
	var supportPicture = !!window.HTMLPictureElement && ('sizes' in document.createElement('img'));

	(function(){
		var prop;
		var noop = function(){};
		var riasDefaults = {
			prefix: '',
			postfix: '',
			srcAttr: 'data-src',
			absUrl: false,
			modifyOptions: noop,
			widthmap: {}
		};

		config = (window.lazySizes && lazySizes.cfg) || window.lazySizesConfig;

		if(!config){
			config = {};
			window.lazySizesConfig = config;
		}

		if(!config.supportsType){
			config.supportsType = function(type/*, elem*/){
				return !type;
			};
		}

		if(!config.rias){
			config.rias = {};
		}
		riasCfg = config.rias;

		if(!('widths' in riasCfg)){
			riasCfg.widths = [];
			(function (widths){
				var width;
				var i = 0;
				while(!width || width < 3000){
					i += 5;
					if(i > 30){
						i += 1;
					}
					width = (36 * i);
					widths.push(width);
				}
			})(riasCfg.widths);
		}

		for(prop in riasDefaults){
			if(!(prop in riasCfg)){
				riasCfg[prop] = riasDefaults[prop];
			}
		}
	})();

	function getElementOptions(elem, src){
		var attr, parent, setOption, options;

		parent = elem.parentNode;
		options = {
			isPicture: !!(parent && regPicture.test(parent.nodeName || ''))
		};

		setOption = function(attr, run){
			var attrVal = elem.getAttribute('data-'+ attr);

			if(attrVal != null){
				if(attrVal == 'true'){
					attrVal = true;
				} else if(attrVal == 'false'){
					attrVal = false;
				} else if(regNumber.test(attrVal)){
					attrVal = parseFloat(attrVal);
				} else if(typeof riasCfg[attr] == 'function'){
					attrVal = riasCfg[attr](elem, attrVal);
				} else if(regObj.test(attrVal)){
					try {
						attrVal = JSON.parse(attrVal);
					} catch(e){}
				}
				options[attr] = attrVal;
			} else if((attr in riasCfg) && typeof riasCfg[attr] != 'function'){
				options[attr] = riasCfg[attr];
			} else if(run && typeof riasCfg[attr] == 'function'){
				options[attr] = riasCfg[attr](elem, attrVal);
			}
		};

		for(attr in riasCfg){
			setOption(attr);
		}
		src.replace(regPlaceholder, function(full, match){
			if(!(match in options)){
				setOption(match, true);
			}
		});

		return options;
	}

	function replaceUrlProps(url, options){
		var candidates = [];
		var replaceFn = function(full, match){
			return (replaceTypes[typeof options[match]]) ? options[match] : full;
		};
		candidates.srcset = [];

		if(options.absUrl){
			anchor.setAttribute('href', url);
			url = anchor.href;
		}

		url = ((options.prefix || '') + url + (options.postfix || '')).replace(regPlaceholder, replaceFn);

		options.widths.forEach(function(width){
			var candidate = {
				u: url.replace(regWidth, options.widthmap[width] || width),
				w: width
			};

			candidates.push(candidate);
			candidates.srcset.push( (candidate.c = candidate.u + ' ' + width + 'w') );
		});
		return candidates;
	}

	function setSrc(src, opts, elem){

		if(!src){return;}

		src = replaceUrlProps(src, opts);

		src.isPicture = opts.isPicture;

		if(buggySizes && elem.nodeName.toUpperCase() == 'IMG'){
			elem.removeAttribute(config.srcsetAttr);
		} else {
			elem.setAttribute(config.srcsetAttr, src.srcset.join(', '));
		}

		Object.defineProperty(elem, '_lazyrias', {
			value: src,
			writable: true
		});
	}

	function createAttrObject(elem, src){
		var opts = getElementOptions(elem, src);

		riasCfg.modifyOptions.call(elem, {target: elem, details: opts, detail: opts});

		lazySizes.fire(elem, 'lazyriasmodifyoptions', opts);
		return opts;
	}

	function getSrc(elem){
		return elem.getAttribute( elem.getAttribute('data-srcattr') || riasCfg.srcAttr ) || elem.getAttribute(config.srcsetAttr) || elem.getAttribute(config.srcAttr) || elem.getAttribute('data-pfsrcset') || '';
	}

	addEventListener('lazybeforeunveil', function(e){
		var elem, src, elemOpts, parent, sources, i, len, sourceSrc, sizes, detail, hasPlaceholder, modified, emptyList;
		elem = e.target;

		if(e.defaultPrevented || riasCfg.disabled || !((sizes = elem.getAttribute(config.sizesAttr) || elem.getAttribute('sizes')) && regAllowedSizes.test(sizes))){return;}

		src = getSrc(elem);

		elemOpts = createAttrObject(elem, src);

		hasPlaceholder = regWidth.test(elemOpts.prefix) || regWidth.test(elemOpts.postfix);

		if(elemOpts.isPicture && (parent = elem.parentNode)){
			sources = parent.getElementsByTagName('source');
			for(i = 0, len = sources.length; i < len; i++){
				if ( hasPlaceholder || regWidth.test(sourceSrc = getSrc(sources[i])) ){
					setSrc(sourceSrc, elemOpts, sources[i]);
					modified = true;
				}
			}
		}

		if ( hasPlaceholder || regWidth.test(src) ){
			setSrc(src, elemOpts, elem);
			modified = true;
		} else if (modified) {
			emptyList = [];
			emptyList.srcset = [];
			emptyList.isPicture = true;
			Object.defineProperty(elem, '_lazyrias', {
				value: emptyList,
				writable: true
			});
		}

		if(modified){
			if(supportPicture){
				elem.removeAttribute(config.srcAttr);
			} else if(sizes != 'auto') {
				detail = {
					width: parseInt(sizes, 10)
				};
				polyfill({
					target: elem,
					detail: detail,
					details: detail
				});
			}
		}
	});
	// partial polyfill
	var polyfill = (function(){
		var ascendingSort = function( a, b ) {
			return a.w - b.w;
		};

		var reduceCandidate = function (srces) {
			var lowerCandidate, bonusFactor;
			var len = srces.length;
			var candidate = srces[len -1];
			var i = 0;

			for(i; i < len;i++){
				candidate = srces[i];
				candidate.d = candidate.w / srces.w;
				if(candidate.d >= srces.d){
					if(!candidate.cached && (lowerCandidate = srces[i - 1]) &&
						lowerCandidate.d > srces.d - (0.13 * Math.pow(srces.d, 2.2))){

						bonusFactor = Math.pow(lowerCandidate.d - 0.6, 1.6);

						if(lowerCandidate.cached) {
							lowerCandidate.d += 0.15 * bonusFactor;
						}

						if(lowerCandidate.d + ((candidate.d - srces.d) * bonusFactor) > srces.d){
							candidate = lowerCandidate;
						}
					}
					break;
				}
			}
			return candidate;
		};

		var getWSet = function(elem, testPicture){
			var src;
			if(!elem._lazyrias && lazySizes.pWS && (src = lazySizes.pWS(elem.getAttribute(config.srcsetAttr || ''))).length){
				Object.defineProperty(elem, '_lazyrias', {
					value: src,
					writable: true
				});
				if(testPicture && elem.parentNode){
					src.isPicture = elem.parentNode.nodeName.toUpperCase() == 'PICTURE';
				}
			}
			return elem._lazyrias;
		};

		var getX = function(elem){
			var dpr = window.devicePixelRatio || 1;
			var optimum = lazySizes.getX && lazySizes.getX(elem);
			return Math.min(optimum || dpr, 2.5, dpr);
		};

		var getCandidate = function(elem, width){
			var sources, i, len, media, srces, src;

			srces = elem._lazyrias;

			if(srces.isPicture && window.matchMedia){
				for(i = 0, sources = elem.parentNode.getElementsByTagName('source'), len = sources.length; i < len; i++){
					if(getWSet(sources[i]) && !sources[i].getAttribute('type') && ( !(media = sources[i].getAttribute('media')) || ((matchMedia(media) || {}).matches))){
						srces = sources[i]._lazyrias;
						break;
					}
				}
			}

			if(!srces.w || srces.w < width){
				srces.w = width;
				srces.d = getX(elem);
				src = reduceCandidate(srces.sort(ascendingSort));
			}

			return src;
		};

		var polyfill = function(e){
			var candidate;
			var elem = e.target;

			if(window.respimage || window.picturefill || lazySizesConfig.pf){
				document.removeEventListener('lazybeforesizes', polyfill);
				return;
			}

			if(!('_lazyrias' in elem) && (!e.detail.dataAttr || !getWSet(elem, true))){
				return;
			}

			candidate = getCandidate(elem, e.detail.width);

			if(candidate && candidate.u && elem._lazyrias.cur != candidate.u){
				elem._lazyrias.cur = candidate.u;
				candidate.cached = true;
				elem.setAttribute(config.srcAttr, candidate.u);
				elem.setAttribute('src', candidate.u);
			}
		};

		if(!supportPicture){
			document.addEventListener('lazybeforesizes', polyfill);
		} else {
			polyfill = function(){};
		}

		return polyfill;

	})();

})(window, document);
<commit_msg>aspect ratio as a custom CSS variable<commit_after>(function(window, document, undefined){
	/*jshint eqnull:true */
	'use strict';

	if(!document.addEventListener){return;}

	var config, riasCfg;
	var replaceTypes = {string: 1, number: 1};
	var regNumber = /^\-*\+*\d+\.*\d*$/;
	var regPicture = /^picture$/i;
	var regWidth = /\s*\{\s*width\s*\}\s*/i;
	var regAspectRatio = /\s*\{\s*aspectratio\s*\}\s*/i;
	var regPlaceholder = /\s*\{\s*([a-z0-9]+)\s*\}\s*/ig;
	var regObj = /^\[.*\]|\{.*\}$/;
	var regAllowedSizes = /^(?:auto|\d+(px)?)$/;
	var anchor = document.createElement('a');
	var img = document.createElement('img');
	var buggySizes = ('srcset' in img) && !('sizes' in img);
	var supportPicture = !!window.HTMLPictureElement && ('sizes' in document.createElement('img'));

	(function(){
		var prop;
		var noop = function(){};
		var riasDefaults = {
			prefix: '',
			postfix: '',
			srcAttr: 'data-src',
			absUrl: false,
			modifyOptions: noop,
			widthmap: {}
		};

		config = (window.lazySizes && lazySizes.cfg) || window.lazySizesConfig;

		if(!config){
			config = {};
			window.lazySizesConfig = config;
		}

		if(!config.supportsType){
			config.supportsType = function(type/*, elem*/){
				return !type;
			};
		}

		if(!config.rias){
			config.rias = {};
		}
		riasCfg = config.rias;

		if(!('widths' in riasCfg)){
			riasCfg.widths = [];
			(function (widths){
				var width;
				var i = 0;
				while(!width || width < 3000){
					i += 5;
					if(i > 30){
						i += 1;
					}
					width = (36 * i);
					widths.push(width);
				}
			})(riasCfg.widths);
		}

		for(prop in riasDefaults){
			if(!(prop in riasCfg)){
				riasCfg[prop] = riasDefaults[prop];
			}
		}
	})();

	function getElementOptions(elem, src){
		var attr, parent, setOption, options;

		parent = elem.parentNode;

		options = {
			isPicture: !!(parent && regPicture.test(parent.nodeName || '')),
		};

		setOption = function(attr, run){
			var attrVal = elem.getAttribute('data-'+ attr);

			if(attrVal != null){
				if(attrVal == 'true'){
					attrVal = true;
				} else if(attrVal == 'false'){
					attrVal = false;
				} else if(regNumber.test(attrVal)){
					attrVal = parseFloat(attrVal);
				} else if(typeof riasCfg[attr] == 'function'){
					attrVal = riasCfg[attr](elem, attrVal);
				} else if(regObj.test(attrVal)){
					try {
						attrVal = JSON.parse(attrVal);
					} catch(e){}
				}
				options[attr] = attrVal;
			} else if((attr in riasCfg) && typeof riasCfg[attr] != 'function'){
				options[attr] = riasCfg[attr];
			} else if(run && typeof riasCfg[attr] == 'function'){
				options[attr] = riasCfg[attr](elem, attrVal);
			}
		};

		for(attr in riasCfg){
			setOption(attr);
		}
		src.replace(regPlaceholder, function(full, match){
			if(!(match in options)){
				setOption(match, true);
			}
		});

		var elemStyles = window.getComputedStyle(elem)
		var aspectRatio = elemStyles.getPropertyValue('--aspect-ratio');

		return options;
	}

	function replaceUrlProps(url, options){
		var candidates = [];
		var replaceFn = function(full, match){
			return (replaceTypes[typeof options[match]]) ? options[match] : full;
		};
		candidates.srcset = [];

		if(options.absUrl){
			anchor.setAttribute('href', url);
			url = anchor.href;
		}

		url = ((options.prefix || '') + url + (options.postfix || '')).replace(regPlaceholder, replaceFn);

		options.widths.forEach(function(width){
			var candidate = {
				u: url.replace(regWidth, options.widthmap[width] || width).replace(regAspectRatio, options['aspectRatio']),
				w: width
			};

			candidates.push(candidate);
			candidates.srcset.push( (candidate.c = candidate.u + ' ' + width + 'w') );
		});

		return candidates;
	}

	function setSrc(src, opts, elem){

		if(!src){return;}

		src = replaceUrlProps(src, opts);

		src.isPicture = opts.isPicture;

		if(buggySizes && elem.nodeName.toUpperCase() == 'IMG'){
			elem.removeAttribute(config.srcsetAttr);
		} else {
			elem.setAttribute(config.srcsetAttr, src.srcset.join(', '));
		}

		Object.defineProperty(elem, '_lazyrias', {
			value: src,
			writable: true
		});
	}

	function createAttrObject(elem, src){
		var opts = getElementOptions(elem, src);

		riasCfg.modifyOptions.call(elem, {target: elem, details: opts, detail: opts});

		lazySizes.fire(elem, 'lazyriasmodifyoptions', opts);
		return opts;
	}

	function getSrc(elem){
		return elem.getAttribute( elem.getAttribute('data-srcattr') || riasCfg.srcAttr ) || elem.getAttribute(config.srcsetAttr) || elem.getAttribute(config.srcAttr) || elem.getAttribute('data-pfsrcset') || '';
	}

	addEventListener('lazybeforeunveil', function(e){
		var elem, src, elemOpts, parent, sources, i, len, sourceSrc, sizes, detail, hasPlaceholder, modified, emptyList;
		elem = e.target;

		if(e.defaultPrevented || riasCfg.disabled || !((sizes = elem.getAttribute(config.sizesAttr) || elem.getAttribute('sizes')) && regAllowedSizes.test(sizes))){return;}

		src = getSrc(elem);

		elemOpts = createAttrObject(elem, src);

		hasPlaceholder = regWidth.test(elemOpts.prefix) || regWidth.test(elemOpts.postfix);

		if(elemOpts.isPicture && (parent = elem.parentNode)){
			sources = parent.getElementsByTagName('source');
			for(i = 0, len = sources.length; i < len; i++){
				if ( hasPlaceholder || regWidth.test(sourceSrc = getSrc(sources[i])) ){
					setSrc(sourceSrc, elemOpts, sources[i]);
					modified = true;
				}
			}
		}

		if ( hasPlaceholder || regWidth.test(src) ){
			setSrc(src, elemOpts, elem);
			modified = true;
		} else if (modified) {
			emptyList = [];
			emptyList.srcset = [];
			emptyList.isPicture = true;
			Object.defineProperty(elem, '_lazyrias', {
				value: emptyList,
				writable: true
			});
		}

		if(modified){
			if(supportPicture){
				elem.removeAttribute(config.srcAttr);
			} else if(sizes != 'auto') {
				detail = {
					width: parseInt(sizes, 10)
				};
				polyfill({
					target: elem,
					detail: detail,
					details: detail
				});
			}
		}
	});
	// partial polyfill
	var polyfill = (function(){
		var ascendingSort = function( a, b ) {
			return a.w - b.w;
		};

		var reduceCandidate = function (srces) {
			var lowerCandidate, bonusFactor;
			var len = srces.length;
			var candidate = srces[len -1];
			var i = 0;

			for(i; i < len;i++){
				candidate = srces[i];
				candidate.d = candidate.w / srces.w;
				if(candidate.d >= srces.d){
					if(!candidate.cached && (lowerCandidate = srces[i - 1]) &&
						lowerCandidate.d > srces.d - (0.13 * Math.pow(srces.d, 2.2))){

						bonusFactor = Math.pow(lowerCandidate.d - 0.6, 1.6);

						if(lowerCandidate.cached) {
							lowerCandidate.d += 0.15 * bonusFactor;
						}

						if(lowerCandidate.d + ((candidate.d - srces.d) * bonusFactor) > srces.d){
							candidate = lowerCandidate;
						}
					}
					break;
				}
			}
			return candidate;
		};

		var getWSet = function(elem, testPicture){
			var src;
			if(!elem._lazyrias && lazySizes.pWS && (src = lazySizes.pWS(elem.getAttribute(config.srcsetAttr || ''))).length){
				Object.defineProperty(elem, '_lazyrias', {
					value: src,
					writable: true
				});
				if(testPicture && elem.parentNode){
					src.isPicture = elem.parentNode.nodeName.toUpperCase() == 'PICTURE';
				}
			}
			return elem._lazyrias;
		};

		var getX = function(elem){
			var dpr = window.devicePixelRatio || 1;
			var optimum = lazySizes.getX && lazySizes.getX(elem);
			return Math.min(optimum || dpr, 2.5, dpr);
		};

		var getCandidate = function(elem, width){
			var sources, i, len, media, srces, src;

			srces = elem._lazyrias;

			if(srces.isPicture && window.matchMedia){
				for(i = 0, sources = elem.parentNode.getElementsByTagName('source'), len = sources.length; i < len; i++){
					if(getWSet(sources[i]) && !sources[i].getAttribute('type') && ( !(media = sources[i].getAttribute('media')) || ((matchMedia(media) || {}).matches))){
						srces = sources[i]._lazyrias;
						break;
					}
				}
			}

			if(!srces.w || srces.w < width){
				srces.w = width;
				srces.d = getX(elem);
				src = reduceCandidate(srces.sort(ascendingSort));
			}

			return src;
		};

		var polyfill = function(e){
			var candidate;
			var elem = e.target;

			if(window.respimage || window.picturefill || lazySizesConfig.pf){
				document.removeEventListener('lazybeforesizes', polyfill);
				return;
			}

			if(!('_lazyrias' in elem) && (!e.detail.dataAttr || !getWSet(elem, true))){
				return;
			}

			candidate = getCandidate(elem, e.detail.width);

			if(candidate && candidate.u && elem._lazyrias.cur != candidate.u){
				elem._lazyrias.cur = candidate.u;
				candidate.cached = true;
				elem.setAttribute(config.srcAttr, candidate.u);
				elem.setAttribute('src', candidate.u);
			}
		};

		if(!supportPicture){
			document.addEventListener('lazybeforesizes', polyfill);
		} else {
			polyfill = function(){};
		}

		return polyfill;

	})();

})(window, document);
<|endoftext|>


<commit_before>/**
 * @fileOverview The file overview and the following infos will be display in the "File Index" of jsDoc
 * @author A. Livet
 * @version 1.0.1
 */

/**
 * Sample that show how to properly document your code for jsdoc
 */

/**
 * @constant This is a constant declaration which will be displayed in the _global_ section of the jsdoc
 */
var acceleration = 9.80665;

Core.Object.extend('Sample.MyObject',
/**
 * The lends tag is used to tell jsdoc that we define an object from a
 * JSON like structure.  The # at the end of the name specify that we
 * are working on the prototype section of the object.  Note that we
 * can't add anything except the class name in the lends tag line.
 * @lends Sample.MyObject#
 */
{
	/**
	 * Event declaration, we must specify the event name cause there
	 * is no function related to them.  Fires on disconnection
     * @name Sample.MyObject#disconnect
     * @event
 	 */
	/**
	 * Fires on a connection to something.
	 * @name Sample.MyObject#connect
 	 * @event
 	 * @param {Boolean} autodisconnect
	 */

	/**
	 * By default, class fields are not included in the
	 * documentation. If you want to expose a field, you need to
	 * surround your comment with jsdoc doclet.  We can define the
	 * default field value with the tag default
     * @default 12
	 */
	myvar: 12,

	//This field won't be included in the documentation cause we do
	//not document it with jsdoc doclet.
	myvar2: undefined,

	/**
	 * This one is a documented field but explicitly ignored.
	 * @ignore
	 */
	myvar4: 42,

	/**
	 * This one is a field treated as a function
	 * @function
	 */
	myvar3: Sample.MyObject.myStaticMethod(),

	//This one will be documented with the property tag
	documentedInConsctructor: 24,

	/**
	 * @constructs This tag precises that this function is the constructor
	 * @class Here we can put the description of the class (we can't put it above the extend call cause we won't have the constructor description otherwise, maybe a jsdoc bug).
	 * Create a new class called MyObject in the namespace Sample.
	 * @extends Core.Object
	 * @property {Number} documentedInConsctructor This is a field documented with the property tag in the constructor,
	 * it's not very elegant but may be usefull in some cases.
	 * @param {Object} config If you want "config" to be display as a function paramter (inside the parenthesis) you must specify the param name config.
	 * @param {Number} config.myvar This is the description of myvar which is a number
	 */
	constructor: function(config) {
		console.log('init Sample.MyObject');
		// check if myvar is present in config.
		// in this case, init with its value
		if('myvar' in config)
			// use "this" to access all method and field
			// of the current instance of the class
			this.myvar = config.myvar;

		//Events are documented at the begining of the class
		this.addEvents('connect', 'disconnect');
	},

	/**
	 * @description The Description tag is implicite on the first comment line, but you can use it
	 * Like all tag, a description can be multi line as long as there is no arobase symbol in it.
	 * Multi line description
	 * We can use the link tag which like the see tag but can be used in others tags like this {@link MyNewNameSpace}
	 * Note the you can't use the link tag in the see tag.
	 * @param {String} myarg1 descrption of myarg1 which is a String
	 * @param {MyNewNameSpace} myarg2 descrption of myarg2 which is an Object documented in the framework (a link will be automatically generated)
	 * @param {Number} [myarg3=1.618] Optional parameter with a default value
	 * @throws {OutOfMemeory} If the function can throw an exception you can add it to the description via the throws tag.
	 * @see The see tag can be use to refere to an hyper text link.
	 * @see MyNewNameSpace or to add a reference to another description
	 * @see Sample.MyObject#deprecatedMethod here it is a reference to an instance member of a class
	 * @see Sample.MyObject.myStaticMethod And here it is a reference to an static member of a class
	 * @example
	 * //The example tag will generate a code snippet, properlly display
	 * var obj = new Sample.MyObject({myvar : 42});
	 * obj.aMethod("foo", new Ui.Button());
	 */
	aMethod: function(myarg1, myarg2, myarg3) {
	},

	/**
	 * @deprecated This is how we mark deprecated method
	 */
	deprecatedMethod: function() {
	},

	/**
	 * This method has been added in version 2.0 so we can use the since tag to specify this.
	 * @since version 2.0
	 */
	newMethod: function() {
	},

	/**
	 * Some times jsdoc complains about function inside function that are not documented
	 * The best way to avois them is to use no-code meta tag (I don't why but the ignore tag doesn't work in that case)
	 */
	jsdocWarningMethod: function(){
		/**#nocode+ Avoid Jsdoc warnings...*/
		var newEvent = {};
		newEvent.preventDefault = function() {};
		/**#nocode-*/
	},

	/**
	 * We can also use the inner tag to tell jsdoc that a function is intern (and also private) and don't need to be documented.
	 */
	jsdocOtherWarningMethod: function(obj){
		var newEvent = {};
		/**@inner*/
		newEvent.preventDefault = function() {};
	},

	/**
	 * This is a defacto private method cause it's prefixed by an underscore.
	 */
	_nativeJsDocPrivateMethod: function(){
	},

	/** @private This method won't be include in the doc unless we use the option -p at the jsdoc generation.*/
	singlePrivateMethod: function(){
	},

	/**#@+ This is a meta tag it will be apply on all the code above until the meta tag closure
	 * @private All the above function will be mark as private
	 */
	otherPrivateMethod: function(){
	},

	andAnotherOnePrivateMethod: function(){
	},

	/**#@- meta tag closure*/

  	/**
	 * An Example of function treated like a field in the doc. Rare case
	 * @field
	 * @type String
	 */
  	fullName: function() {
    	return this.myvar + this.myvar2;
 	}
},
/**
 * Function override are also part of the object prototype
 * @lends Sample.MyObject#
 */
{
	/**
	 * @see Core.Object#toString Use the see tag to link to another description.
	 * Don't use the borrows tag to copy description from another class cause it's buggy and experimental
	 */
	toString: function() {
		// when you override a method, you can always called
		// the overrided method with the following syntax:
		var res = Sample.MyObject.base.toString.call(this);
		return("Sample.MyObject ("+res+")");
	}
},
/**
 * And it's how we document the static part (without #)
 * @lends Sample.MyObject
 */
{
	/**
	 * declare a static field. To access its value
	 * @example Sample.MyObject.myStaticField
	 */
	myStaticField: 32,

	/**
	 * the static constructor is called only once when the class is
	 * declared. In this constructor, "this" correspond to Sample.MyObject
	 */
	constructor: function() {
	},

	/**
	 * declare a static method.
	 * @example Sample.MyObject.myStaticMethod();
	 */
	myStaticMethod: function() {
	}

});

/**
 * Here I describe the constructor
 * @class This is a classical class+constructor description
 */
Classic = function () {
};

/**
 * Classical method of a non Core.Object class
 */
Classic.prototype.method = function() {
}
<commit_msg>remove error<commit_after>/**
 * @fileOverview The file overview and the following infos will be display in the "File Index" of jsDoc
 * @author A. Livet
 * @version 1.0.1
 */

/**
 * Sample that show how to properly document your code for jsdoc
 */

/**
 * @constant This is a constant declaration which will be displayed in the _global_ section of the jsdoc
 */
var acceleration = 9.80665;

Core.Object.extend('Sample.MyObject',
/**
 * The lends tag is used to tell jsdoc that we define an object from a
 * JSON like structure.  The # at the end of the name specify that we
 * are working on the prototype section of the object.  Note that we
 * can't add anything except the class name in the lends tag line.
 * @lends Sample.MyObject#
 */
{
	/**
	 * Event declaration, we must specify the event name cause there
	 * is no function related to them.  Fires on disconnection
     * @name Sample.MyObject#disconnect
     * @event
 	 */
	/**
	 * Fires on a connection to something.
	 * @name Sample.MyObject#connect
 	 * @event
 	 * @param {Boolean} autodisconnect
	 */

	/**
	 * By default, class fields are not included in the
	 * documentation. If you want to expose a field, you need to
	 * surround your comment with jsdoc doclet.  We can define the
	 * default field value with the tag default
     * @default 12
	 */
	myvar: 12,

	//This field won't be included in the documentation cause we do
	//not document it with jsdoc doclet.
	myvar2: undefined,

	/**
	 * This one is a documented field but explicitly ignored.
	 * @ignore
	 */
	myvar4: 42,

	//This one will be documented with the property tag
	documentedInConsctructor: 24,

	/**
	 * @constructs This tag precises that this function is the constructor
	 * @class Here we can put the description of the class (we can't put it above the extend call cause we won't have the constructor description otherwise, maybe a jsdoc bug).
	 * Create a new class called MyObject in the namespace Sample.
	 * @extends Core.Object
	 * @property {Number} documentedInConsctructor This is a field documented with the property tag in the constructor,
	 * it's not very elegant but may be usefull in some cases.
	 * @param {Object} config If you want "config" to be display as a function paramter (inside the parenthesis) you must specify the param name config.
	 * @param {Number} config.myvar This is the description of myvar which is a number
	 */
	constructor: function(config) {
		console.log('init Sample.MyObject');
		// check if myvar is present in config.
		// in this case, init with its value
		if('myvar' in config)
			// use "this" to access all method and field
			// of the current instance of the class
			this.myvar = config.myvar;

		//Events are documented at the begining of the class
		this.addEvents('connect', 'disconnect');
	},

	/**
	 * @description The Description tag is implicite on the first comment line, but you can use it
	 * Like all tag, a description can be multi line as long as there is no arobase symbol in it.
	 * Multi line description
	 * We can use the link tag which like the see tag but can be used in others tags like this {@link MyNewNameSpace}
	 * Note the you can't use the link tag in the see tag.
	 * @param {String} myarg1 descrption of myarg1 which is a String
	 * @param {MyNewNameSpace} myarg2 descrption of myarg2 which is an Object documented in the framework (a link will be automatically generated)
	 * @param {Number} [myarg3=1.618] Optional parameter with a default value
	 * @throws {OutOfMemeory} If the function can throw an exception you can add it to the description via the throws tag.
	 * @see The see tag can be use to refere to an hyper text link.
	 * @see MyNewNameSpace or to add a reference to another description
	 * @see Sample.MyObject#deprecatedMethod here it is a reference to an instance member of a class
	 * @see Sample.MyObject.myStaticMethod And here it is a reference to an static member of a class
	 * @example
	 * //The example tag will generate a code snippet, properlly display
	 * var obj = new Sample.MyObject({myvar : 42});
	 * obj.aMethod("foo", new Ui.Button());
	 */
	aMethod: function(myarg1, myarg2, myarg3) {
	},

	/**
	 * @deprecated This is how we mark deprecated method
	 */
	deprecatedMethod: function() {
	},

	/**
	 * This method has been added in version 2.0 so we can use the since tag to specify this.
	 * @since version 2.0
	 */
	newMethod: function() {
	},

	/**
	 * Some times jsdoc complains about function inside function that are not documented
	 * The best way to avois them is to use no-code meta tag (I don't why but the ignore tag doesn't work in that case)
	 */
	jsdocWarningMethod: function(){
		/**#nocode+ Avoid Jsdoc warnings...*/
		var newEvent = {};
		newEvent.preventDefault = function() {};
		/**#nocode-*/
	},

	/**
	 * We can also use the inner tag to tell jsdoc that a function is intern (and also private) and don't need to be documented.
	 */
	jsdocOtherWarningMethod: function(obj){
		var newEvent = {};
		/**@inner*/
		newEvent.preventDefault = function() {};
	},

	/**
	 * This is a defacto private method cause it's prefixed by an underscore.
	 */
	_nativeJsDocPrivateMethod: function(){
	},

	/** @private This method won't be include in the doc unless we use the option -p at the jsdoc generation.*/
	singlePrivateMethod: function(){
	},

	/**#@+ This is a meta tag it will be apply on all the code above until the meta tag closure
	 * @private All the above function will be mark as private
	 */
	otherPrivateMethod: function(){
	},

	andAnotherOnePrivateMethod: function(){
	},

	/**#@- meta tag closure*/

  	/**
	 * An Example of function treated like a field in the doc. Rare case
	 * @field
	 * @type String
	 */
  	fullName: function() {
    	return this.myvar + this.myvar2;
 	}
},
/**
 * Function override are also part of the object prototype
 * @lends Sample.MyObject#
 */
{
	/**
	 * @see Core.Object#toString Use the see tag to link to another description.
	 * Don't use the borrows tag to copy description from another class cause it's buggy and experimental
	 */
	toString: function() {
		// when you override a method, you can always called
		// the overrided method with the following syntax:
		var res = Sample.MyObject.base.toString.call(this);
		return("Sample.MyObject ("+res+")");
	}
},
/**
 * And it's how we document the static part (without #)
 * @lends Sample.MyObject
 */
{
	/**
	 * declare a static field. To access its value
	 * @example Sample.MyObject.myStaticField
	 */
	myStaticField: 32,

	/**
	 * the static constructor is called only once when the class is
	 * declared. In this constructor, "this" correspond to Sample.MyObject
	 */
	constructor: function() {
	},

	/**
	 * declare a static method.
	 * @example Sample.MyObject.myStaticMethod();
	 */
	myStaticMethod: function() {
	}

});

/**
 * Here I describe the constructor
 * @class This is a classical class+constructor description
 */
Classic = function () {
};

/**
 * Classical method of a non Core.Object class
 */
Classic.prototype.method = function() {
}
<|endoftext|>


<commit_before><commit_msg>tweak order, someones video would fail to start<commit_after><|endoftext|>


<commit_before>/*jslint node: true */
"use strict";
var Emitter        = require('events').EventEmitter,
    os             = require('os'),
    util           = require('util'),
    SSDP           = require('node-ssdp'),
    netmask        = require('netmask'),
    Device         = require('./samsung-airconditioner');

var DEFAULT_LOGGER = {
  error   : function(msg, props) { console.log(msg); if (!!props) console.trace(props.exception); },
  warning : function(msg, props) { console.log(msg); if (!!props) console.log(props);             },
  notice  : function(msg, props) { console.log(msg); if (!!props) console.log(props);             },
  info    : function(msg, props) { console.log(msg); if (!!props) console.log(props);             },
  debug   : function(msg, props) { console.log(msg); if (!!props) console.log(props);             }
};

var SamsungDiscovery = function(options) {
  var ifa, ifaces, ifaddrs, ifname, k;

  var self = this;

  if (!(self instanceof SamsungDiscovery)) return new SamsungDiscovery(options);

  self.options = options || {};

  self.logger = self.options.logger || {};
  for (k in DEFAULT_LOGGER) {
    if ((DEFAULT_LOGGER.hasOwnProperty(k)) && (typeof self.logger[k] === 'undefined'))  self.logger[k] = DEFAULT_LOGGER[k];
  }

  self.devices = {};

  ifaces = os.networkInterfaces();
  for (ifname in ifaces) {
    if ((!ifaces.hasOwnProperty(ifname)) ||
        (ifname.indexOf('vmnet') === 0)  ||
        (ifname.indexOf('vnic') === 0)   ||
        (ifname.indexOf('tun') !== -1)) {
      continue;
    }

    ifaddrs = ifaces[ifname];
    if (ifaddrs.length === 0) continue;

    for (ifa = 0; ifa < ifaddrs.length; ifa++) {
      if ((ifaddrs[ifa].internal) || (ifaddrs[ifa].family !== 'IPv4')) continue;

      self.logger.info('listening', {
        network_interface: ifname,
        ipaddr: ifaddrs[ifa].address,
        portno: 1900
      });
      self.listen(ifname, ifaddrs[ifa].address, 1900);
    }
  }
};
util.inherits(SamsungDiscovery, Emitter);

SamsungDiscovery.prototype.listen = function(ifname, ipaddr, portno) {
  var self = this;

  var notify = function() {
    ssdp.notify(ifname, ipaddr, portno, 'AIR CONDITIONER',
                { SPEC_VER: 'MSpec-1.00', SERVICE_NAME: 'ControlServer-MLib', MESSAGE_TYPE: 'CONTROLLER_START' });
  };

  var ssdp = new SSDP({
    addMembership     : false,
    responsesOnly     : true,
    multicastLoopback : false,
    noAdvertisements  : true
  }).on('response', function(msg, rinfo) {
    var i, info, j, lines, mac;

    lines = msg.toString().split("\r\n");
    info = {};
    for (i = 1; i < lines.length; i++) {
      j = lines[i].indexOf(':');
      if (j <= 0) break;
      info[lines[i].substring(0, j)] = lines[i].substring(j + 1).trim();
    }

    mac = info.MAC_ADDR;
    self.devices[mac] = new Device({
      logger : self.logger,
      ip     : rinfo.address,
      duid   : mac,
      info   : info
    });

    self.emit('discover', self.devices[mac]);
  });
  ssdp.logger = self.logger;

  ssdp.server('0.0.0.0');
  ssdp.sock.on('listening', function() {
    setInterval(notify, 30 * 1000);
    notify();
  });
};

SSDP.prototype.notify = function(ifname, ipaddr, portno, signature, vars) {/* jshint unused: false */
  var out;

  var self = this;

  if (!self.listening) return;

  Object.keys(self.usns).forEach(function (usn) {
    var bcast, mask, quad0;

    var udn   = self.usns[usn],
        heads ={
          HOST            : '239.255.255.250:1900',
          'CACHE-CONTROL' : 'max-age=20',
          SERVER          : signature
        };

    out = self.getSSDPHeader('NOTIFY', heads);
    Object.keys(vars).forEach(function (n) { out += n + ': ' + vars[n] + '\r\n'; });

    quad0 = parseInt(ipaddr.split('.')[0], 10);
    mask = ((quad0 & 0x80) === 0) ? 8 : ((quad0 & 0xc0) === 0xf0) ? 16 : 24;

// TBD: use the (obsolete) class A/B/C netmasks
    bcast = new netmask.Netmask(ipaddr + '/' + mask).broadcast;
    self.logger.info('multicasting', { interface: ifname, ipaddr: bcast, portno: 1900 });

    out = new Buffer(out);
    self.sock.setBroadcast(true);
    self.sock.send(out, 0, out.length, 1900, bcast);
  });
};

module.exports = SamsungDiscovery;
<commit_msg>jshint<commit_after>/*jslint node: true */
"use strict";
var Emitter        = require('events').EventEmitter,
    os             = require('os'),
    util           = require('util'),
    SSDP           = require('node-ssdp'),
    netmask        = require('netmask'),
    Device         = require('./samsung-airconditioner');

var DEFAULT_LOGGER = {
  error   : function(msg, props) { console.log(msg); if (!!props) console.trace(props.exception); },
  warning : function(msg, props) { console.log(msg); if (!!props) console.log(props);             },
  notice  : function(msg, props) { console.log(msg); if (!!props) console.log(props);             },
  info    : function(msg, props) { console.log(msg); if (!!props) console.log(props);             },
  debug   : function(msg, props) { console.log(msg); if (!!props) console.log(props);             }
};

var SamsungDiscovery = function(options) {
  var ifa, ifaces, ifaddrs, ifname, k;

  var self = this;

  if (!(self instanceof SamsungDiscovery)) return new SamsungDiscovery(options);

  self.options = options || {};

  self.logger = self.options.logger || {};
  for (k in DEFAULT_LOGGER) {
    if ((DEFAULT_LOGGER.hasOwnProperty(k)) && (typeof self.logger[k] === 'undefined'))  self.logger[k] = DEFAULT_LOGGER[k];
  }

  self.devices = {};

  ifaces = os.networkInterfaces();
  for (ifname in ifaces) {
    if ((!ifaces.hasOwnProperty(ifname)) ||
        (ifname.indexOf('vmnet') === 0)  ||
        (ifname.indexOf('vnic') === 0)   ||
        (ifname.indexOf('tun') !== -1)) {
      continue;
    }

    ifaddrs = ifaces[ifname];
    if (ifaddrs.length === 0) continue;

    for (ifa = 0; ifa < ifaddrs.length; ifa++) {
      if ((ifaddrs[ifa].internal) || (ifaddrs[ifa].family !== 'IPv4')) continue;

      self.logger.info('listening', {
        network_interface: ifname,
        ipaddr: ifaddrs[ifa].address,
        portno: 1900
      });
      self.listen(ifname, ifaddrs[ifa].address, 1900);
    }
  }
};
util.inherits(SamsungDiscovery, Emitter);

SamsungDiscovery.prototype.listen = function(ifname, ipaddr, portno) {
  var self = this;

  var notify = function() {
    ssdp.notify(ifname, ipaddr, portno, 'AIR CONDITIONER',
                { SPEC_VER: 'MSpec-1.00', SERVICE_NAME: 'ControlServer-MLib', MESSAGE_TYPE: 'CONTROLLER_START' });
  };

  var ssdp = new SSDP({
    addMembership     : false,
    responsesOnly     : true,
    multicastLoopback : false,
    noAdvertisements  : true
  }).on('response', function(msg, rinfo) {
    var i, info, j, lines, mac;

    lines = msg.toString().split("\r\n");
    info = {};
    for (i = 1; i < lines.length; i++) {
      j = lines[i].indexOf(':');
      if (j <= 0) break;
      info[lines[i].substring(0, j)] = lines[i].substring(j + 1).trim();
    }

    mac = info.MAC_ADDR;
    self.devices[mac] = new Device({
      logger : self.logger,
      ip     : rinfo.address,
      duid   : mac,
      info   : info
    });

    self.emit('discover', self.devices[mac]);
  });
  ssdp.logger = self.logger;

  ssdp.server('0.0.0.0');
  ssdp.sock.on('listening', function() {
    setInterval(notify, 30 * 1000);
    notify();
  });
};

SSDP.prototype.notify = function(ifname, ipaddr, portno, signature, vars) {/* jshint unused: false */
  var out;

  var self = this;

  if (!self.listening) return;

  Object.keys(self.usns).forEach(function (usn) {
    var bcast, mask, quad0;

    var udn   = self.usns[usn],
        heads ={
          HOST            : '239.255.255.250:1900',
          'CACHE-CONTROL' : 'max-age=20',
          SERVER          : signature
        };

    out = self.getSSDPHeader('NOTIFY', heads);
    Object.keys(vars).forEach(function (n) { out += n + ': ' + vars[n] + '\r\n'; });

    quad0 = parseInt(ipaddr.split('.')[0], 10);
    mask = ((quad0 & 0x80) === 0) ? 8 : ((quad0 & 0xc0) === 0xf0) ? 16 : 24;

// TBD: use the (obsolete) class A/B/C netmasks
    bcast = new netmask.Netmask(ipaddr + '/' + mask).broadcast;
    self.logger.info('multicasting', {
      network_interface: ifname,
      ipaddr: bcast,
      portno: 1900
    });

    out = new Buffer(out);
    self.sock.setBroadcast(true);
    self.sock.send(out, 0, out.length, 1900, bcast);
  });
};

module.exports = SamsungDiscovery;
<|endoftext|>


<commit_before>/*jslint white: true */
/*global exports, String, Buffer, require, console */

exports.SamsungController = exports.SamsungController || (function () {
  'use strict';

  /**
   * @author brian@bevey.org
   * @fileoverview Basic control over Samsung SmartTVs from 2011 onward via TCP
   *               web sockets using Node.js.
   * @note This is a full-scale rip-off of the fine work done here:
   *       http://forum.samygo.tv/viewtopic.php?f=12&t=1792
   */
  return {
    version : '0.0.0.0.1 alpha',
    /**
     * Whitelist of available key codes to use.
     */
    keymap  : ['0', '1', '16_9', '2', '3', '3SPEED', '4', '5', '6', '7', '8', '9', '11', '12', '4_3', 'AD', 'ADDDEL', 'ALT_MHP', 'ANGLE', 'ANTENA', 'ANYNET', 'ANYVIEW', 'APP_LIST', 'ASPECT', 'AUTO_ARC_ANTENNA_AIR', 'AUTO_ARC_ANTENNA_CABLE', 'AUTO_ARC_ANTENNA_SATELLITE', 'AUTO_ARC_ANYNET_AUTO_START', 'AUTO_ARC_ANYNET_MODE_OK', 'AUTO_ARC_AUTOCOLOR_FAIL', 'AUTO_ARC_AUTOCOLOR_SUCCESS', 'AUTO_ARC_CAPTION_ENG', 'AUTO_ARC_CAPTION_KOR', 'AUTO_ARC_CAPTION_OFF', 'AUTO_ARC_CAPTION_ON', 'AUTO_ARC_C_FORCE_AGING', 'AUTO_ARC_JACK_IDENT', 'AUTO_ARC_LNA_OFF', 'AUTO_ARC_LNA_ON', 'AUTO_ARC_PIP_CH_CHANGE', 'AUTO_ARC_PIP_DOUBLE', 'AUTO_ARC_PIP_LARGE', 'AUTO_ARC_PIP_LEFT_BOTTOM', 'AUTO_ARC_PIP_LEFT_TOP', 'AUTO_ARC_PIP_RIGHT_BOTTOM', 'AUTO_ARC_PIP_RIGHT_TOP', 'AUTO_ARC_PIP_SMALL', 'AUTO_ARC_PIP_SOURCE_CHANGE', 'AUTO_ARC_PIP_WIDE', 'AUTO_ARC_RESET', 'AUTO_ARC_USBJACK_INSPECT', 'AUTO_FORMAT', 'AUTO_PROGRAM', 'AV1', 'AV2', 'AV3', 'BACK_MHP', 'BOOKMARK', 'CALLER_ID', 'CAPTION', 'CATV_MODE', 'CHDOWN', 'CHUP', 'CH_LIST', 'CLEAR', 'CLOCK_DISPLAY', 'COMPONENT1', 'COMPONENT2', 'CONTENTS', 'CONVERGENCE', 'CONVERT_AUDIO_MAINSUB', 'CUSTOM', 'CYAN', 'DEVICE_CONNECT', 'DISC_MENU', 'DMA', 'DNET', 'DNIe', 'DNSe', 'DOOR', 'DOWN', 'DSS_MODE', 'DTV', 'DTV_LINK', 'DTV_SIGNAL', 'DVD_MODE', 'DVI', 'DVR', 'DVR_MENU', 'DYNAMIC', 'ENTER', 'ENTERTAINMENT', 'ESAVING', 'EXT1', 'EXT10', 'EXT11', 'EXT12', 'EXT13', 'EXT14', 'EXT15', 'EXT16', 'EXT17', 'EXT18', 'EXT19', 'EXT2', 'EXT20', 'EXT21', 'EXT22', 'EXT23', 'EXT24', 'EXT25', 'EXT26', 'EXT27', 'EXT28', 'EXT29', 'EXT3', 'EXT30', 'EXT31', 'EXT32', 'EXT33', 'EXT34', 'EXT35', 'EXT36', 'EXT37', 'EXT38', 'EXT39', 'EXT4', 'EXT40', 'EXT41', 'EXT5', 'EXT6', 'EXT7', 'EXT8', 'EXT9', 'FACTORY', 'FAVCH', 'FF', 'FF_', 'FM_RADIO', 'GAME', 'GREEN', 'GUIDE', 'HDMI', 'HDMI1', 'HDMI2', 'HDMI3', 'HDMI4', 'HELP', 'HOME', 'ID_INPUT', 'ID_SETUP', 'INFO', 'INSTANT_REPLAY', 'LEFT', 'LINK', 'LIVE', 'MAGIC_BRIGHT', 'MAGIC_CHANNEL', 'MDC', 'MENU', 'MIC', 'MORE', 'MOVIE1', 'MS', 'MTS', 'MUTE', 'NINE_SEPERATE', 'OPEN', 'PANNEL_CHDOWN', 'PANNEL_CHUP', 'PANNEL_ENTER', 'PANNEL_MENU', 'PANNEL_POWER', 'PANNEL_SOURCE', 'PANNEL_VOLDOW', 'PANNEL_VOLUP', 'PANORAMA', 'PAUSE', 'PCMODE', 'PERPECT_FOCUS', 'PICTURE_SIZE', 'PIP_CHDOWN', 'PIP_CHUP', 'PIP_ONOFF', 'PIP_SCAN', 'PIP_SIZE', 'PIP_SWAP', 'PLAY', 'PLUS100', 'PMODE', 'POWER', 'POWEROFF', 'POWERON', 'PRECH', 'PRINT', 'PROGRAM', 'QUICK_REPLAY', 'REC', 'RED', 'REPEAT', 'RESERVED1', 'RETURN', 'REWIND', 'REWIND_', 'RIGHT', 'RSS', 'RSURF', 'SCALE', 'SEFFECT', 'SETUP_CLOCK_TIMER', 'SLEEP', 'SOURCE', 'SRS', 'STANDARD', 'STB_MODE', 'STILL_PICTURE', 'STOP', 'SUB_TITLE', 'SVIDEO1', 'SVIDEO2', 'SVIDEO3', 'TOOLS', 'TOPMENU', 'TTX_MIX', 'TTX_SUBFACE', 'TURBO', 'TV', 'TV_MODE', 'UP', 'VCHIP', 'VCR_MODE', 'VOLDOWN', 'VOLUP', 'WHEEL_LEFT', 'WHEEL_RIGHT', 'W_LINK', 'YELLOW', 'ZOOM1', 'ZOOM2', 'ZOOM_IN', 'ZOOM_MOVE', 'ZOOM_OUT'],

    base64_encode : function (string) {
      return new Buffer(string).toString('base64');
    },

    /**
     * Once the connection has been established, this chunk seems to validate
     * input source.
     * "This is who I am."
     */
    chunkOne : function () {
      var ipencoded  = this.base64_encode(this.serverip),
          macencoded = this.base64_encode(this.servermac),
          message    = String.fromCharCode(0x64) + String.fromCharCode(0x00) + String.fromCharCode(ipencoded.length) + String.fromCharCode(0x00) + ipencoded + String.fromCharCode(macencoded.length) + String.fromCharCode(0x00) + macencoded + String.fromCharCode(this.base64_encode(this.remotename).length) + String.fromCharCode(0x00) + this.base64_encode(this.remotename);

      return String.fromCharCode(0x00) + String.fromCharCode(this.appstring.length) + String.fromCharCode(0x00) + this.appstring + String.fromCharCode(message.length) + String.fromCharCode(0x00) + message;
    },

    /**
     * This chunk seems to tell the TV which command to execute - or, text to
     * be inputted into fields.
     * "Will you please do this for me?"
     */
    chunkTwo : function () {
      var command = 'KEY_' + this.command,
          message = '';

      if(this.command) {
console.log('command sent: ' + this.command);
        message = String.fromCharCode(0x00) + String.fromCharCode(0x00) + String.fromCharCode(0x00) + String.fromCharCode(this.base64_encode(command).length) + String.fromCharCode(0x00) + this.base64_encode(command);

        console.log('Executing: ' + this.command);

        return String.fromCharCode(0x00) + String.fromCharCode(this.tvappstring.length) + String.fromCharCode(0x00) + this.tvappstring + String.fromCharCode(message.length) + String.fromCharCode(0x00) + message;
      }

      if(this.text) {
console.log('text sent');
        message = String.fromCharCode(0x01) + String.fromCharCode(0x00) + String.fromCharCode(this.base64_encode(this.text).length) + String.fromCharCode(0x00) + this.base64_encode(this.text);

        console.log('Text: ' + this.text);

        return String.fromCharCode(0x01) + String.fromCharCode(this.appstring.length) + String.fromCharCode(0x00) + this.appstring + String.fromCharCode(message.length) + String.fromCharCode(0x00) + message;
      }
    },

    send : function (config) {
      this.tvip        = config.tvip;
      this.serverip    = config.serverip;
      this.servermac   = config.servermac;
      this.command     = config.command     || '';
      this.text        = config.text        || '';
      this.tvport      = config.tvport      || 55000;
      this.appstring   = config.appstring   || "iphone..iapp.samsung";
      this.tvappstring = config.tvappstring || "iphone.UN60ES8000.iapp.samsung";
      this.remotename  = config.remotename  || "Node.js Samsung Remote";
      this.cbConnect   = config.cbConnect   || function () {};
      this.cbError     = config.cbError     || function () {};

      var that         = this,
          net          = require('net'),
          socket       = net.connect(this.tvport, this.tvip);

      socket.on('connect', function() {
        console.log('connected');

        socket.write(that.chunkOne());
        socket.write(that.chunkTwo());

        socket.end();

        that.cbConnect();
      });

      socket.on('error', function(error) {
        var errorMsg = '';

        if(error.code === 'EHOSTUNREACH' || error.code === 'ECONNREFUSED') {
          errorMsg = 'TV is off or unreachable';
        }

        else {
          errorMsg = error.code;
        }

        console.log(errorMsg);

        that.cbError(errorMsg);
      });
    }
  };
} ());<commit_msg>Remove debug logging<commit_after>/*jslint white: true */
/*global exports, String, Buffer, require, console */

exports.SamsungController = exports.SamsungController || (function () {
  'use strict';

  /**
   * @author brian@bevey.org
   * @fileoverview Basic control over Samsung SmartTVs from 2011 onward via TCP
   *               web sockets using Node.js.
   * @note This is a full-scale rip-off of the fine work done here:
   *       http://forum.samygo.tv/viewtopic.php?f=12&t=1792
   */
  return {
    version : '0.0.0.0.1 alpha',
    /**
     * Whitelist of available key codes to use.
     */
    keymap  : ['0', '1', '16_9', '2', '3', '3SPEED', '4', '5', '6', '7', '8', '9', '11', '12', '4_3', 'AD', 'ADDDEL', 'ALT_MHP', 'ANGLE', 'ANTENA', 'ANYNET', 'ANYVIEW', 'APP_LIST', 'ASPECT', 'AUTO_ARC_ANTENNA_AIR', 'AUTO_ARC_ANTENNA_CABLE', 'AUTO_ARC_ANTENNA_SATELLITE', 'AUTO_ARC_ANYNET_AUTO_START', 'AUTO_ARC_ANYNET_MODE_OK', 'AUTO_ARC_AUTOCOLOR_FAIL', 'AUTO_ARC_AUTOCOLOR_SUCCESS', 'AUTO_ARC_CAPTION_ENG', 'AUTO_ARC_CAPTION_KOR', 'AUTO_ARC_CAPTION_OFF', 'AUTO_ARC_CAPTION_ON', 'AUTO_ARC_C_FORCE_AGING', 'AUTO_ARC_JACK_IDENT', 'AUTO_ARC_LNA_OFF', 'AUTO_ARC_LNA_ON', 'AUTO_ARC_PIP_CH_CHANGE', 'AUTO_ARC_PIP_DOUBLE', 'AUTO_ARC_PIP_LARGE', 'AUTO_ARC_PIP_LEFT_BOTTOM', 'AUTO_ARC_PIP_LEFT_TOP', 'AUTO_ARC_PIP_RIGHT_BOTTOM', 'AUTO_ARC_PIP_RIGHT_TOP', 'AUTO_ARC_PIP_SMALL', 'AUTO_ARC_PIP_SOURCE_CHANGE', 'AUTO_ARC_PIP_WIDE', 'AUTO_ARC_RESET', 'AUTO_ARC_USBJACK_INSPECT', 'AUTO_FORMAT', 'AUTO_PROGRAM', 'AV1', 'AV2', 'AV3', 'BACK_MHP', 'BOOKMARK', 'CALLER_ID', 'CAPTION', 'CATV_MODE', 'CHDOWN', 'CHUP', 'CH_LIST', 'CLEAR', 'CLOCK_DISPLAY', 'COMPONENT1', 'COMPONENT2', 'CONTENTS', 'CONVERGENCE', 'CONVERT_AUDIO_MAINSUB', 'CUSTOM', 'CYAN', 'DEVICE_CONNECT', 'DISC_MENU', 'DMA', 'DNET', 'DNIe', 'DNSe', 'DOOR', 'DOWN', 'DSS_MODE', 'DTV', 'DTV_LINK', 'DTV_SIGNAL', 'DVD_MODE', 'DVI', 'DVR', 'DVR_MENU', 'DYNAMIC', 'ENTER', 'ENTERTAINMENT', 'ESAVING', 'EXT1', 'EXT10', 'EXT11', 'EXT12', 'EXT13', 'EXT14', 'EXT15', 'EXT16', 'EXT17', 'EXT18', 'EXT19', 'EXT2', 'EXT20', 'EXT21', 'EXT22', 'EXT23', 'EXT24', 'EXT25', 'EXT26', 'EXT27', 'EXT28', 'EXT29', 'EXT3', 'EXT30', 'EXT31', 'EXT32', 'EXT33', 'EXT34', 'EXT35', 'EXT36', 'EXT37', 'EXT38', 'EXT39', 'EXT4', 'EXT40', 'EXT41', 'EXT5', 'EXT6', 'EXT7', 'EXT8', 'EXT9', 'FACTORY', 'FAVCH', 'FF', 'FF_', 'FM_RADIO', 'GAME', 'GREEN', 'GUIDE', 'HDMI', 'HDMI1', 'HDMI2', 'HDMI3', 'HDMI4', 'HELP', 'HOME', 'ID_INPUT', 'ID_SETUP', 'INFO', 'INSTANT_REPLAY', 'LEFT', 'LINK', 'LIVE', 'MAGIC_BRIGHT', 'MAGIC_CHANNEL', 'MDC', 'MENU', 'MIC', 'MORE', 'MOVIE1', 'MS', 'MTS', 'MUTE', 'NINE_SEPERATE', 'OPEN', 'PANNEL_CHDOWN', 'PANNEL_CHUP', 'PANNEL_ENTER', 'PANNEL_MENU', 'PANNEL_POWER', 'PANNEL_SOURCE', 'PANNEL_VOLDOW', 'PANNEL_VOLUP', 'PANORAMA', 'PAUSE', 'PCMODE', 'PERPECT_FOCUS', 'PICTURE_SIZE', 'PIP_CHDOWN', 'PIP_CHUP', 'PIP_ONOFF', 'PIP_SCAN', 'PIP_SIZE', 'PIP_SWAP', 'PLAY', 'PLUS100', 'PMODE', 'POWER', 'POWEROFF', 'POWERON', 'PRECH', 'PRINT', 'PROGRAM', 'QUICK_REPLAY', 'REC', 'RED', 'REPEAT', 'RESERVED1', 'RETURN', 'REWIND', 'REWIND_', 'RIGHT', 'RSS', 'RSURF', 'SCALE', 'SEFFECT', 'SETUP_CLOCK_TIMER', 'SLEEP', 'SOURCE', 'SRS', 'STANDARD', 'STB_MODE', 'STILL_PICTURE', 'STOP', 'SUB_TITLE', 'SVIDEO1', 'SVIDEO2', 'SVIDEO3', 'TOOLS', 'TOPMENU', 'TTX_MIX', 'TTX_SUBFACE', 'TURBO', 'TV', 'TV_MODE', 'UP', 'VCHIP', 'VCR_MODE', 'VOLDOWN', 'VOLUP', 'WHEEL_LEFT', 'WHEEL_RIGHT', 'W_LINK', 'YELLOW', 'ZOOM1', 'ZOOM2', 'ZOOM_IN', 'ZOOM_MOVE', 'ZOOM_OUT'],

    base64_encode : function (string) {
      return new Buffer(string).toString('base64');
    },

    /**
     * Once the connection has been established, this chunk seems to validate
     * input source.
     * "This is who I am."
     */
    chunkOne : function () {
      var ipencoded  = this.base64_encode(this.serverip),
          macencoded = this.base64_encode(this.servermac),
          message    = String.fromCharCode(0x64) + String.fromCharCode(0x00) + String.fromCharCode(ipencoded.length) + String.fromCharCode(0x00) + ipencoded + String.fromCharCode(macencoded.length) + String.fromCharCode(0x00) + macencoded + String.fromCharCode(this.base64_encode(this.remotename).length) + String.fromCharCode(0x00) + this.base64_encode(this.remotename);

      return String.fromCharCode(0x00) + String.fromCharCode(this.appstring.length) + String.fromCharCode(0x00) + this.appstring + String.fromCharCode(message.length) + String.fromCharCode(0x00) + message;
    },

    /**
     * This chunk seems to tell the TV which command to execute - or, text to
     * be inputted into fields.
     * "Will you please do this for me?"
     */
    chunkTwo : function () {
      var command = 'KEY_' + this.command,
          message = '';

      if(this.command) {
        message = String.fromCharCode(0x00) + String.fromCharCode(0x00) + String.fromCharCode(0x00) + String.fromCharCode(this.base64_encode(command).length) + String.fromCharCode(0x00) + this.base64_encode(command);

        console.log('Executing: ' + this.command);

        return String.fromCharCode(0x00) + String.fromCharCode(this.tvappstring.length) + String.fromCharCode(0x00) + this.tvappstring + String.fromCharCode(message.length) + String.fromCharCode(0x00) + message;
      }

      if(this.text) {
        message = String.fromCharCode(0x01) + String.fromCharCode(0x00) + String.fromCharCode(this.base64_encode(this.text).length) + String.fromCharCode(0x00) + this.base64_encode(this.text);

        console.log('Text: ' + this.text);

        return String.fromCharCode(0x01) + String.fromCharCode(this.appstring.length) + String.fromCharCode(0x00) + this.appstring + String.fromCharCode(message.length) + String.fromCharCode(0x00) + message;
      }
    },

    send : function (config) {
      this.tvip        = config.tvip;
      this.serverip    = config.serverip;
      this.servermac   = config.servermac;
      this.command     = config.command     || '';
      this.text        = config.text        || '';
      this.tvport      = config.tvport      || 55000;
      this.appstring   = config.appstring   || "iphone..iapp.samsung";
      this.tvappstring = config.tvappstring || "iphone.UN60ES8000.iapp.samsung";
      this.remotename  = config.remotename  || "Node.js Samsung Remote";
      this.cbConnect   = config.cbConnect   || function () {};
      this.cbError     = config.cbError     || function () {};

      var that         = this,
          net          = require('net'),
          socket       = net.connect(this.tvport, this.tvip);

      socket.on('connect', function() {
        console.log('connected');

        socket.write(that.chunkOne());
        socket.write(that.chunkTwo());

        socket.end();

        that.cbConnect();
      });

      socket.on('error', function(error) {
        var errorMsg = '';

        if(error.code === 'EHOSTUNREACH' || error.code === 'ECONNREFUSED') {
          errorMsg = 'TV is off or unreachable';
        }

        else {
          errorMsg = error.code;
        }

        console.log(errorMsg);

        that.cbError(errorMsg);
      });
    }
  };
} ());<|endoftext|>


<commit_before><commit_msg>catch 401 => logout<commit_after><|endoftext|>


<commit_before><commit_msg>new version<commit_after><|endoftext|>


<commit_before><commit_msg>Added env value to start log.<commit_after><|endoftext|>