<commit_before>module.exports = SteamTradeOffers;

var request = require('request');
var cheerio = require('cheerio');
var Long = require('long');
var querystring = require('querystring');

require('util').inherits(SteamTradeOffers, require('events').EventEmitter);

function SteamTradeOffers() {
  require('events').EventEmitter.call(this);

  this._j = request.jar();
  this._request = request.defaults({jar:this._j});
}

SteamTradeOffers.prototype.setup = function(options, callback){
  var self = this;

  this.sessionID = options.sessionID;

  options.webCookie.forEach(function(name){
    setCookie(self, name);
  });

  getAPIKey(this, callback);
};

function getAPIKey(self, callback) {
  self._request.get({
    uri: 'https://steamcommunity.com/dev/apikey'
  }, function(error, response, body) {
    if (error || response.statusCode != 200) {
      self.emit('debug', 'retrieving apikey: ' + (error || response.statusCode));
      getAPIKey(self, callback);
    } else {
      var $ = cheerio.load(body);
      if ($('#mainContents h2').html() == 'Access Denied') {
        self.emit('debug', 'retrieving apikey: access denied (probably limited account)');
        self.APIKey = '';
        var error = new Error('Access Denied');
        if(typeof callback == 'function'){
          callback(error);
        } else {
          throw error;
        }
      } else if($('#bodyContents_ex h2').html() == 'Your Steam Web API Key'){
        var key = $('#bodyContents_ex p').html().split(' ')[1];
        self.APIKey = key;
        if(typeof callback == 'function'){
          callback();
        }
      } else {
        self._request.post({
          uri: 'https://steamcommunity.com/dev/registerkey',
          form: {
            domain: 'localhost',
            agreeToTerms: 1
          }
        }, function(error, response, body) {
          getAPIKey(self, callback);
        }.bind(self));
      }
    }
  }.bind(self));
}

function setCookie(self, cookie) {
  self._j.add(request.cookie(cookie));
}

SteamTradeOffers.prototype._loadInventory = function(inventory, uri, options, contextid, start, callback) {
  options.uri = uri;

  if (start) {
    options.uri = options.uri + '&' + querystring.stringify({ 'start': start });
  }

  this._request.get(options, function(error, response, body) {
    if (error || response.statusCode != 200 || JSON.stringify(body) == '{}') {
      this.emit('debug', 'loading inventory: ' + (error || (response.statusCode != 200 ? response.statusCode : '{}')));
      this._loadInventory(inventory, uri, options, contextid, start, callback);
    } else if (typeof body != 'object') {
      // no session
      if(typeof callback == 'function'){
        callback(new Error('No session'));
      }
    } else if (body.success == false) {
      // inventory not found
      if(typeof callback == 'function'){
        callback(new Error('Inventory not found'));
      }
    } else if (Object.prototype.toString.apply(body) == '[object Array]') {
      //private inventory
      if(typeof callback == 'function'){
        callback(new Error('Inventory is private'));
      }
    } else {
      inventory = inventory.concat(mergeWithDescriptions(body.rgInventory, body.rgDescriptions, contextid)
        .concat(mergeWithDescriptions(body.rgCurrency, body.rgDescriptions, contextid)));
      if (body.more) {
        this._loadInventory(inventory, uri, options, contextid, body.more_start, callback);
      } else {
        if(typeof callback == 'function'){
          callback(null, inventory);
        }
      }
    }
  }.bind(this));
};

SteamTradeOffers.prototype.loadMyInventory = function(options, callback) {
  var self = this;

  var uri = 'https://steamcommunity.com/my/inventory/json/' + options.appId + '/' + options.contextId + '/?trading=1';

  this._loadInventory([], uri, { json: true }, options.contextId, null, callback);
};

SteamTradeOffers.prototype.loadPartnerInventory = function(options, callback) {
  var self = this;

  var form = {
    sessionid: this.sessionID,
    partner: options.partnerSteamId,
    appid: options.appId,
    contextid: options.contextId
  };

  var offer = 'new';
  if (options.tradeOfferId) {
    offer = options.tradeOfferId;
  }

  var uri = 'https://steamcommunity.com/tradeoffer/' + offer + '/partnerinventory/?' + querystring.stringify(form);

  this._loadInventory([], uri, {
    json: true,
    headers: {
      referer: 'https://steamcommunity.com/tradeoffer/' + offer + '/?partner=' + toAccountId(options.partnerSteamId)
    }
  }, options.contextId, null, callback);
};

function mergeWithDescriptions(items, descriptions, contextid) {
  return Object.keys(items).map(function(id) {
    var item = items[id];
    var description = descriptions[item.classid + '_' + (item.instanceid || '0')];
    for (var key in description) {
      item[key] = description[key];
    }
    // add contextid because Steam is retarded
    item.contextid = contextid;
    return item;
  });
}

function doAPICall(self, options) {
  var request_params = {
    uri: 'https://api.steampowered.com/IEconService/' + options.method + '/?key=' + self.APIKey + ((options.post) ? '' : '&' + querystring.stringify(options.params)),
    json: true,
    method: options.post ? 'POST' : 'GET'
  };

  if (options.post) {
    request_params.form = options.params;
  }

  request(request_params, function(error, response, body) {
    if (error || response.statusCode != 200) {
      self.emit('debug', 'doing API call ' + options.method + ': ' + (error || response.statusCode));
      if(typeof options.callback == 'function'){
        options.callback(error || new Error(response.statusCode));
      }
    } else if (typeof body != 'object') {
      if(typeof options.callback == 'function'){
        options.callback(new Error('Invalid response'));
      }
    } else {
      if(typeof options.callback == 'function'){
        options.callback(null, body);
      }
    }
  });
}

SteamTradeOffers.prototype.getOffers = function(options, callback) {
  doAPICall(this, {
    method: 'GetTradeOffers/v1',
    params: options,
    callback: function(error, res) {
      if (error) {
        if(typeof callback == 'function'){
          callback(error);
        }
      } else {
        if (res.response.trade_offers_received !== undefined) {
          res.response.trade_offers_received = res.response.trade_offers_received.map(function(offer) {
            offer.steamid_other = toSteamId(offer.accountid_other);
            return offer;
          });
        }
        if (res.response.trade_offers_sent !== undefined) {
          res.response.trade_offers_sent = res.response.trade_offers_sent.map(function(offer) {
            offer.steamid_other = toSteamId(offer.accountid_other);
            return offer;
          });
        }
        if(typeof callback == 'function'){
          callback(null, res);
        }
      }
    }
  });
};

SteamTradeOffers.prototype.getOffer = function(options, callback) {
  doAPICall(this, {
    method: 'GetTradeOffer/v1',
    params: options,
    callback: function(error, res) {
      if (error) {
        if(typeof callback == 'function'){
          callback(error);
        }
      } else {
        res.response.offer.steamid_other = toSteamId(res.response.offer.accountid_other);
        if(typeof callback == 'function'){
          callback(null, res);
        }
      }
    }
  });
};

SteamTradeOffers.prototype.declineOffer = function(options, callback) {
  doAPICall(this, {method: 'DeclineTradeOffer/v1', params: {tradeofferid: options.tradeOfferId}, post: true, callback: callback});
};

SteamTradeOffers.prototype.cancelOffer = function(options, callback) {
  doAPICall(this, {method: 'CancelTradeOffer/v1', params: {tradeofferid: options.tradeOfferId}, post: true, callback: callback});
};

SteamTradeOffers.prototype.acceptOffer = function(options, callback) {
  if (typeof options.tradeOfferId == 'undefined') {
    if(typeof callback == 'function'){
      callback(new Error('No options'));
    }
  } else {
    this._request.post({
      uri: 'https://steamcommunity.com/tradeoffer/' + options.tradeOfferId + '/accept',
      headers: {
        referer: 'https://steamcommunity.com/tradeoffer/' + options.tradeOfferId + '/'
      },
      form: {
        sessionid: this.sessionID,
        tradeofferid: options.tradeOfferId
      }
    }, function(error, response, body) {
      if (error || response.statusCode != 200) {
        if(typeof callback == 'function'){
          callback(error || new Error(response.statusCode));
        }
      } else {
        if(typeof callback == 'function'){
          callback(null, {response:{}});
        }
      }
    });
  }
};

function toSteamId(accountId) {
  return new Long(parseInt(accountId, 10), 0x1100001).toString();
}

function toAccountId(steamId) {
  return Long.fromString(steamId).toInt().toString();
}

SteamTradeOffers.prototype.makeOffer = function(options, callback) {
  var self = this;

  var tradeoffer = {
    "newversion":true,
    "version":2,
    "me":{"assets": options.itemsFromMe,"currency":[],"ready":false},
    "them":{"assets": options.itemsFromThem,"currency":[],"ready":false}
  };

  var formFields = {
    sessionid: this.sessionID,
    partner: options.partnerSteamId || toSteamId(options.partnerAccountId),
    tradeoffermessage: options.message || "",
    json_tradeoffer: JSON.stringify(tradeoffer)
  };

  var query = {
    partner: options.partnerAccountId || toAccountId(options.partnerSteamId)
  };

  if(typeof options.accessToken != 'undefined'){
    formFields.trade_offer_create_params = JSON.stringify({ trade_offer_access_token: options.accessToken });
    query.token = options.accessToken;
  };

  if (typeof options.counteredTradeOffer != 'undefined') {
    formFields.tradeofferid_countered = options.counteredTradeOffer;
    var referer = 'https://steamcommunity.com/tradeoffer/' + options.counteredTradeOffer + '/';
  }
  else {
    var referer = 'https://steamcommunity.com/tradeoffer/new/?' + querystring.stringify(query);
  }

  this._request.post({
    uri: 'https://steamcommunity.com/tradeoffer/new/send',
    headers: {
      referer: referer
    },
    form: formFields
  }, function(error, response, body) {
    var result = {};
    try {
      result = JSON.parse(body) || {};
    } catch(e) {
      if(typeof callback == 'function'){
        return callback(e);
      }
    }

    if (error || response.statusCode != 200) {
      self.emit('debug', 'making an offer: ' + (error || response.statusCode));
      if(typeof callback == 'function'){
        callback(error || new Error(result.strError || response.statusCode));
      }
    } else {
      if(typeof callback == 'function'){
        callback(null, result);
      }
    }
  });
};
<commit_msg>better handling of results and errors in acceptOffer<commit_after>module.exports = SteamTradeOffers;

var request = require('request');
var cheerio = require('cheerio');
var Long = require('long');
var querystring = require('querystring');

require('util').inherits(SteamTradeOffers, require('events').EventEmitter);

function SteamTradeOffers() {
  require('events').EventEmitter.call(this);

  this._j = request.jar();
  this._request = request.defaults({jar:this._j});
}

SteamTradeOffers.prototype.setup = function(options, callback){
  var self = this;

  this.sessionID = options.sessionID;

  options.webCookie.forEach(function(name){
    setCookie(self, name);
  });

  getAPIKey(this, callback);
};

function getAPIKey(self, callback) {
  self._request.get({
    uri: 'https://steamcommunity.com/dev/apikey'
  }, function(error, response, body) {
    if (error || response.statusCode != 200) {
      self.emit('debug', 'retrieving apikey: ' + (error || response.statusCode));
      getAPIKey(self, callback);
    } else {
      var $ = cheerio.load(body);
      if ($('#mainContents h2').html() == 'Access Denied') {
        self.emit('debug', 'retrieving apikey: access denied (probably limited account)');
        self.APIKey = '';
        var error = new Error('Access Denied');
        if(typeof callback == 'function'){
          callback(error);
        } else {
          throw error;
        }
      } else if($('#bodyContents_ex h2').html() == 'Your Steam Web API Key'){
        var key = $('#bodyContents_ex p').html().split(' ')[1];
        self.APIKey = key;
        if(typeof callback == 'function'){
          callback();
        }
      } else {
        self._request.post({
          uri: 'https://steamcommunity.com/dev/registerkey',
          form: {
            domain: 'localhost',
            agreeToTerms: 1
          }
        }, function(error, response, body) {
          getAPIKey(self, callback);
        }.bind(self));
      }
    }
  }.bind(self));
}

function setCookie(self, cookie) {
  self._j.add(request.cookie(cookie));
}

SteamTradeOffers.prototype._loadInventory = function(inventory, uri, options, contextid, start, callback) {
  options.uri = uri;

  if (start) {
    options.uri = options.uri + '&' + querystring.stringify({ 'start': start });
  }

  this._request.get(options, function(error, response, body) {
    if (error || response.statusCode != 200 || JSON.stringify(body) == '{}') {
      this.emit('debug', 'loading inventory: ' + (error || (response.statusCode != 200 ? response.statusCode : '{}')));
      this._loadInventory(inventory, uri, options, contextid, start, callback);
    } else if (typeof body != 'object') {
      // no session
      if(typeof callback == 'function'){
        callback(new Error('No session'));
      }
    } else if (body.success == false) {
      // inventory not found
      if(typeof callback == 'function'){
        callback(new Error('Inventory not found'));
      }
    } else if (Object.prototype.toString.apply(body) == '[object Array]') {
      //private inventory
      if(typeof callback == 'function'){
        callback(new Error('Inventory is private'));
      }
    } else {
      inventory = inventory.concat(mergeWithDescriptions(body.rgInventory, body.rgDescriptions, contextid)
        .concat(mergeWithDescriptions(body.rgCurrency, body.rgDescriptions, contextid)));
      if (body.more) {
        this._loadInventory(inventory, uri, options, contextid, body.more_start, callback);
      } else {
        if(typeof callback == 'function'){
          callback(null, inventory);
        }
      }
    }
  }.bind(this));
};

SteamTradeOffers.prototype.loadMyInventory = function(options, callback) {
  var self = this;

  var uri = 'https://steamcommunity.com/my/inventory/json/' + options.appId + '/' + options.contextId + '/?trading=1';

  this._loadInventory([], uri, { json: true }, options.contextId, null, callback);
};

SteamTradeOffers.prototype.loadPartnerInventory = function(options, callback) {
  var self = this;

  var form = {
    sessionid: this.sessionID,
    partner: options.partnerSteamId,
    appid: options.appId,
    contextid: options.contextId
  };

  var offer = 'new';
  if (options.tradeOfferId) {
    offer = options.tradeOfferId;
  }

  var uri = 'https://steamcommunity.com/tradeoffer/' + offer + '/partnerinventory/?' + querystring.stringify(form);

  this._loadInventory([], uri, {
    json: true,
    headers: {
      referer: 'https://steamcommunity.com/tradeoffer/' + offer + '/?partner=' + toAccountId(options.partnerSteamId)
    }
  }, options.contextId, null, callback);
};

function mergeWithDescriptions(items, descriptions, contextid) {
  return Object.keys(items).map(function(id) {
    var item = items[id];
    var description = descriptions[item.classid + '_' + (item.instanceid || '0')];
    for (var key in description) {
      item[key] = description[key];
    }
    // add contextid because Steam is retarded
    item.contextid = contextid;
    return item;
  });
}

function doAPICall(self, options) {
  var request_params = {
    uri: 'https://api.steampowered.com/IEconService/' + options.method + '/?key=' + self.APIKey + ((options.post) ? '' : '&' + querystring.stringify(options.params)),
    json: true,
    method: options.post ? 'POST' : 'GET'
  };

  if (options.post) {
    request_params.form = options.params;
  }

  request(request_params, function(error, response, body) {
    if (error || response.statusCode != 200) {
      self.emit('debug', 'doing API call ' + options.method + ': ' + (error || response.statusCode));
      if(typeof options.callback == 'function'){
        options.callback(error || new Error(response.statusCode));
      }
    } else if (typeof body != 'object') {
      if(typeof options.callback == 'function'){
        options.callback(new Error('Invalid response'));
      }
    } else {
      if(typeof options.callback == 'function'){
        options.callback(null, body);
      }
    }
  });
}

SteamTradeOffers.prototype.getOffers = function(options, callback) {
  doAPICall(this, {
    method: 'GetTradeOffers/v1',
    params: options,
    callback: function(error, res) {
      if (error) {
        if(typeof callback == 'function'){
          callback(error);
        }
      } else {
        if (res.response.trade_offers_received !== undefined) {
          res.response.trade_offers_received = res.response.trade_offers_received.map(function(offer) {
            offer.steamid_other = toSteamId(offer.accountid_other);
            return offer;
          });
        }
        if (res.response.trade_offers_sent !== undefined) {
          res.response.trade_offers_sent = res.response.trade_offers_sent.map(function(offer) {
            offer.steamid_other = toSteamId(offer.accountid_other);
            return offer;
          });
        }
        if(typeof callback == 'function'){
          callback(null, res);
        }
      }
    }
  });
};

SteamTradeOffers.prototype.getOffer = function(options, callback) {
  doAPICall(this, {
    method: 'GetTradeOffer/v1',
    params: options,
    callback: function(error, res) {
      if (error) {
        if(typeof callback == 'function'){
          callback(error);
        }
      } else {
        res.response.offer.steamid_other = toSteamId(res.response.offer.accountid_other);
        if(typeof callback == 'function'){
          callback(null, res);
        }
      }
    }
  });
};

SteamTradeOffers.prototype.declineOffer = function(options, callback) {
  doAPICall(this, {method: 'DeclineTradeOffer/v1', params: {tradeofferid: options.tradeOfferId}, post: true, callback: callback});
};

SteamTradeOffers.prototype.cancelOffer = function(options, callback) {
  doAPICall(this, {method: 'CancelTradeOffer/v1', params: {tradeofferid: options.tradeOfferId}, post: true, callback: callback});
};

SteamTradeOffers.prototype.acceptOffer = function(options, callback) {
  if (typeof options.tradeOfferId == 'undefined') {
    if(typeof callback == 'function'){
      callback(new Error('No options'));
    }
  } else {
    this._request.post({
      uri: 'https://steamcommunity.com/tradeoffer/' + options.tradeOfferId + '/accept',
      headers: {
        referer: 'https://steamcommunity.com/tradeoffer/' + options.tradeOfferId + '/'
      },
      form: {
        sessionid: this.sessionID,
        tradeofferid: options.tradeOfferId
      }
    }, function(error, response, body) {
      var result = {};
      try {
        result = JSON.parse(body) || {};
      } catch(e) {
        if(typeof callback == 'function'){
          return callback(e);
        }
      }

      if (error || response.statusCode != 200) {
        self.emit('debug', 'accepting offer: ' + (error || response.statusCode));
        if(typeof callback == 'function'){
          callback(error || new Error(result.strError || response.statusCode));
        }
      } else {
        if(typeof callback == 'function'){
          callback(null, result);
        }
      }
    });
  }
};

function toSteamId(accountId) {
  return new Long(parseInt(accountId, 10), 0x1100001).toString();
}

function toAccountId(steamId) {
  return Long.fromString(steamId).toInt().toString();
}

SteamTradeOffers.prototype.makeOffer = function(options, callback) {
  var self = this;

  var tradeoffer = {
    "newversion":true,
    "version":2,
    "me":{"assets": options.itemsFromMe,"currency":[],"ready":false},
    "them":{"assets": options.itemsFromThem,"currency":[],"ready":false}
  };

  var formFields = {
    sessionid: this.sessionID,
    partner: options.partnerSteamId || toSteamId(options.partnerAccountId),
    tradeoffermessage: options.message || "",
    json_tradeoffer: JSON.stringify(tradeoffer)
  };

  var query = {
    partner: options.partnerAccountId || toAccountId(options.partnerSteamId)
  };

  if(typeof options.accessToken != 'undefined'){
    formFields.trade_offer_create_params = JSON.stringify({ trade_offer_access_token: options.accessToken });
    query.token = options.accessToken;
  };

  if (typeof options.counteredTradeOffer != 'undefined') {
    formFields.tradeofferid_countered = options.counteredTradeOffer;
    var referer = 'https://steamcommunity.com/tradeoffer/' + options.counteredTradeOffer + '/';
  }
  else {
    var referer = 'https://steamcommunity.com/tradeoffer/new/?' + querystring.stringify(query);
  }

  this._request.post({
    uri: 'https://steamcommunity.com/tradeoffer/new/send',
    headers: {
      referer: referer
    },
    form: formFields
  }, function(error, response, body) {
    var result = {};
    try {
      result = JSON.parse(body) || {};
    } catch(e) {
      if(typeof callback == 'function'){
        return callback(e);
      }
    }

    if (error || response.statusCode != 200) {
      self.emit('debug', 'making an offer: ' + (error || response.statusCode));
      if(typeof callback == 'function'){
        callback(error || new Error(result.strError || response.statusCode));
      }
    } else {
      if(typeof callback == 'function'){
        callback(null, result);
      }
    }
  });
};
<|endoftext|>


<commit_before>$(document).ready(function(){

	var intro = $("#main_intro");
	var projects = $("#projects");
	var blog = $("#blog");
	var contact = $("#contact");

	$(link).hover(function(){
		$(link).animate({height: "50px"}, {duration:'slow', queue: false});
		$(link).animate({width: "300px"}, {duration:'slow', queue: false});
		$("#link img").animate({width: "50px"}, {duration:'slow', queue: false});
		$("#link img").animate({height: "50px"}, {duration:'slow', queue: false});
		$("#link").css("background-color", "#B25E24");

	},
	function(){
		$(link).animate({height: "30px"}, {duration: 'slow', queue: false});
		$(link).animate({width: "130px"}, {duration: 'slow', queue: false});
		$("#link img").animate({width: "20px"}, {duration:'slow', queue: false});
		$("#link img").animate({height: "20px"}, {duration:'slow', queue: false});
		$("#link").css("background-color", "#FF7819");

	})

	if (intro.hasClass("tabbed") == true){
		alert("passed");
	}
	if (projects.hasClass("tabbed") == true){
		alert("passed");
	}
	if (blog.hasClass("tabbed") == true){
		alert("passed");
	}
	if (contact.hasClass("tabbed") == true){
		alert("passed");
	}

	var tabLinks = new Array();
    var contentDivs = new Array();

    function init() {

      // Grab the tab links and content divs from the page
      var tabListItems = document.getElementById('tabs').childNodes;
      for ( var i = 0; i < tabListItems.length; i++ ) {
        if ( tabListItems[i].nodeName == "LI" ) {
          var tabLink = getFirstChildWithTagName( tabListItems[i], 'A' );
          var id = getHash( tabLink.getAttribute('href') );
          tabLinks[id] = tabLink;
          contentDivs[id] = document.getElementById( id );
        }
      }

      // Assign onclick events to the tab links, and
      // highlight the first tab
      var i = 0;

      for ( var id in tabLinks ) {
        tabLinks[id].onclick = showTab;
        tabLinks[id].onfocus = function() { this.blur() };
        if ( i == 0 ) tabLinks[id].className = 'selected';
        i++;
      }

      // Hide all content divs except the first
      var i = 0;

      for ( var id in contentDivs ) {
        if ( i != 0 ) contentDivs[id].className = 'tabContent hide';
        i++;
      }
    }

    function showTab() {
      var selectedId = getHash( this.getAttribute('href') );

      // Highlight the selected tab, and dim all others.
      // Also show the selected content div, and hide all others.
      for ( var id in contentDivs ) {
        if ( id == selectedId ) {
          tabLinks[id].className = 'selected';
          contentDivs[id].className = 'tabContent';
        } else {
          tabLinks[id].className = '';
          contentDivs[id].className = 'tabContent hide';
        }
      }

      // Stop the browser following the link
      return false;
    }

    function getFirstChildWithTagName( element, tagName ) {
      for ( var i = 0; i < element.childNodes.length; i++ ) {
        if ( element.childNodes[i].nodeName == tagName ) return element.childNodes[i];
      }
    }

    function getHash( url ) {
      var hashPos = url.lastIndexOf ( '#' );
      return url.substring( hashPos + 1 );
    }

    //]]>
})<commit_msg>js fixes<commit_after>$(document).ready(function(){

	var intro = $("#main_intro");
	var projects = $("#projects");
	var blog = $("#blog");
	var contact = $("#contact");

	if (intro.hasClass("tabbed") == true){
		alert("passed");
	}
	if (projects.hasClass("tabbed") == true){
		alert("passed");
	}
	if (blog.hasClass("tabbed") == true){
		alert("passed");
	}
	if (contact.hasClass("tabbed") == true){
		alert("passed");
	}

	var tabLinks = new Array();
    var contentDivs = new Array();

    function init() {

      // Grab the tab links and content divs from the page
      var tabListItems = document.getElementById('tabs').childNodes;
      for ( var i = 0; i < tabListItems.length; i++ ) {
        if ( tabListItems[i].nodeName == "LI" ) {
          var tabLink = getFirstChildWithTagName( tabListItems[i], 'A' );
          var id = getHash( tabLink.getAttribute('href') );
          tabLinks[id] = tabLink;
          contentDivs[id] = document.getElementById( id );
        }
      }

      // Assign onclick events to the tab links, and
      // highlight the first tab
      var i = 0;

      for ( var id in tabLinks ) {
        tabLinks[id].onclick = showTab;
        tabLinks[id].onfocus = function() { this.blur() };
        if ( i == 0 ) tabLinks[id].className = 'selected';
        i++;
      }

      // Hide all content divs except the first
      var i = 0;

      for ( var id in contentDivs ) {
        if ( i != 0 ) contentDivs[id].className = 'tabContent hide';
        i++;
      }
    }

    function showTab() {
      var selectedId = getHash( this.getAttribute('href') );

      // Highlight the selected tab, and dim all others.
      // Also show the selected content div, and hide all others.
      for ( var id in contentDivs ) {
        if ( id == selectedId ) {
          tabLinks[id].className = 'selected';
          contentDivs[id].className = 'tabContent';
        } else {
          tabLinks[id].className = '';
          contentDivs[id].className = 'tabContent hide';
        }
      }

      // Stop the browser following the link
      return false;
    }

    function getFirstChildWithTagName( element, tagName ) {
      for ( var i = 0; i < element.childNodes.length; i++ ) {
        if ( element.childNodes[i].nodeName == tagName ) return element.childNodes[i];
      }
    }

    function getHash( url ) {
      var hashPos = url.lastIndexOf ( '#' );
      return url.substring( hashPos + 1 );
    }

    //]]>
})
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var fs2 = require('../fs2');
var md5hex = require('../md5hex');
var Processor = require('../processor');
var listFiles = require('../list-files');
var Batch = require('../batch');
var promisify = require('../promisify');
var mkdirp = promisify(require('mkdirp'));

var processor = new Processor();

function unixPathJoin() {
	return _.toArray(arguments).join('/');
}

function removeEmptyDirs(dir) {
	try {
		var filePaths = fs.readdirSync(dir).filter(function(filePath) {
			filePath = unixPathJoin(dir, filePath);
			var stat = fs.lstatSync(filePath);
			return !(stat && stat.isDirectory() && removeEmptyDirs(filePath));
		});

		if (filePaths.length === 0) {
			fs.rmdirSync(dir);
			return true;
		}
	} catch (error) {}

	return false;
}

function getBuildDir(distDir, distPaths) {
	var paths = distPaths.map(function(distPath) {
		return distPath.substr(distDir.length + 1);
	});
	var buildPath = _.find(paths, function(path) {
		return path.indexOf('build-') === 0;
	});
	return buildPath ? distDir + '/' + buildPath.substr(0, buildPath.indexOf('/')) : null;
}

processor.getBatches = function(inputPaths) {
	var log = this.log;
	var distDir = this.config.project.distDir;

	var oldPaths = listFiles(distDir);
	var newPaths = inputPaths.map(function(inputPath) {
		return unixPathJoin(distDir, inputPath);
	});

	// Rename any old build-xxx to new build-yyy dir to reduce number of differences
	var oldBuildDir = getBuildDir(distDir, oldPaths);
	var newBuildDir = getBuildDir(distDir, newPaths);
	if (oldBuildDir && newBuildDir && (oldBuildDir !== newBuildDir)) {
		log.ok('%s => %s', oldBuildDir, newBuildDir);
		fs.renameSync(oldBuildDir, newBuildDir);
		oldPaths = oldPaths.map(function(oldPath) {
			return oldPath.replace(oldBuildDir, newBuildDir);
		});
	}

	// Remove files that are no longer in inputPaths
	_.difference(oldPaths, newPaths).forEach(function(removedPath) {
		log.ok('Removed: %s', removedPath);
		fs.unlinkSync(removedPath);
	});

	// Remove empty directories left behind after removing files
	removeEmptyDirs(distDir);

	return inputPaths.map(function(inputPath) {
		return new Batch([ { path: inputPath, type: 'buffer', isReadOnly: true } ], [], { doNotCache: true });
	});
};

processor.process = function(inputs) {
	var log = this.log;
	var input = inputs[0];
	var buffer = input.data;
	var inputPath = input.path;
	var outputPath = unixPathJoin(this.config.project.distDir, inputPath);

	return fs2.readFile(outputPath).then(md5hex, function() {
		return undefined; // MD5 of non-existing file should not be a failure (just empty)
	}).then(function(oldMD5) {
		if (input.md5 === oldMD5) {
			log.spam('Unchanged: %s', outputPath);
		} else {
			return mkdirp(path.dirname(outputPath)).then(function() {
				return fs2.writeFile(outputPath, buffer).then(function() {
					log.ok('%s: %s', oldMD5 ? 'Changed' : 'Added', outputPath);
				});
			});
		}
	});
};

module.exports = processor;
<commit_msg>Added try-catch around fs.renameSync of old build dir to new build dir in dist processor to work around Windows sometimes throwing EPERM, operation not permitted<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var fs2 = require('../fs2');
var md5hex = require('../md5hex');
var Processor = require('../processor');
var listFiles = require('../list-files');
var Batch = require('../batch');
var promisify = require('../promisify');
var mkdirp = promisify(require('mkdirp'));

var processor = new Processor();

function unixPathJoin() {
	return _.toArray(arguments).join('/');
}

function removeEmptyDirs(dir) {
	try {
		var filePaths = fs.readdirSync(dir).filter(function(filePath) {
			filePath = unixPathJoin(dir, filePath);
			var stat = fs.lstatSync(filePath);
			return !(stat && stat.isDirectory() && removeEmptyDirs(filePath));
		});

		if (filePaths.length === 0) {
			fs.rmdirSync(dir);
			return true;
		}
	} catch (error) {}

	return false;
}

function getBuildDir(distDir, distPaths) {
	var paths = distPaths.map(function(distPath) {
		return distPath.substr(distDir.length + 1);
	});
	var buildPath = _.find(paths, function(path) {
		return path.indexOf('build-') === 0;
	});
	return buildPath ? distDir + '/' + buildPath.substr(0, buildPath.indexOf('/')) : null;
}

processor.getBatches = function(inputPaths) {
	var log = this.log;
	var distDir = this.config.project.distDir;

	var oldPaths = listFiles(distDir);
	var newPaths = inputPaths.map(function(inputPath) {
		return unixPathJoin(distDir, inputPath);
	});

	// Rename any old build-xxx to new build-yyy dir to reduce number of differences
	var oldBuildDir = getBuildDir(distDir, oldPaths);
	var newBuildDir = getBuildDir(distDir, newPaths);
	if (oldBuildDir && newBuildDir && (oldBuildDir !== newBuildDir)) {
		log.ok('%s => %s', oldBuildDir, newBuildDir);
		try {
			fs.renameSync(oldBuildDir, newBuildDir);
			oldPaths = oldPaths.map(function(oldPath) {
				return oldPath.replace(oldBuildDir, newBuildDir);
			});
		} catch (error) {
			// Sometimes, I don't understand why, Windows throws: EPERM, operation not permitted
			// Not renaming is inefficient, but not fatal, so at least for now, I will just catch and warn
			log.warn('Build dir rename failed: %s', error.message);
		}
	}

	// Remove files that are no longer in inputPaths
	_.difference(oldPaths, newPaths).forEach(function(removedPath) {
		log.ok('Removed: %s', removedPath);
		fs.unlinkSync(removedPath);
	});

	// Remove empty directories left behind after removing files
	removeEmptyDirs(distDir);

	return inputPaths.map(function(inputPath) {
		return new Batch([ { path: inputPath, type: 'buffer', isReadOnly: true } ], [], { doNotCache: true });
	});
};

processor.process = function(inputs) {
	var log = this.log;
	var input = inputs[0];
	var buffer = input.data;
	var inputPath = input.path;
	var outputPath = unixPathJoin(this.config.project.distDir, inputPath);

	return fs2.readFile(outputPath).then(md5hex, function() {
		return undefined; // MD5 of non-existing file should not be a failure (just empty)
	}).then(function(oldMD5) {
		if (input.md5 === oldMD5) {
			log.spam('Unchanged: %s', outputPath);
		} else {
			return mkdirp(path.dirname(outputPath)).then(function() {
				return fs2.writeFile(outputPath, buffer).then(function() {
					log.ok('%s: %s', oldMD5 ? 'Changed' : 'Added', outputPath);
				});
			});
		}
	});
};

module.exports = processor;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {
  DeviceEventEmitter, // android
  NativeAppEventEmitter, // ios
  NativeModules,
  Platform,
  StyleSheet,
  requireNativeComponent,
  View,
} from 'react-native';

const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule;
const CAMERA_REF = 'camera';

function convertNativeProps(props) {
  const newProps = { ...props };
  if (typeof props.aspect === 'string') {
    newProps.aspect = Camera.constants.Aspect[props.aspect];
  }

  if (typeof props.flashMode === 'string') {
    newProps.flashMode = Camera.constants.FlashMode[props.flashMode];
  }

  if (typeof props.orientation === 'string') {
    newProps.orientation = Camera.constants.Orientation[props.orientation];
  }

  if (typeof props.torchMode === 'string') {
    newProps.torchMode = Camera.constants.TorchMode[props.torchMode];
  }

  if (typeof props.type === 'string') {
    newProps.type = Camera.constants.Type[props.type];
  }

  if (typeof props.captureQuality === 'string') {
    newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality];
  }

  if (typeof props.captureMode === 'string') {
    newProps.captureMode = Camera.constants.CaptureMode[props.captureMode];
  }

  // do not register barCodeTypes if no barcode listener
  if (typeof props.onBarCodeRead !== 'function') {
    newProps.barCodeTypes = [];
  }

  newProps.barcodeScannerEnabled = typeof props.onBarCodeRead === 'function'

  return newProps;
}

export default class Camera extends Component {

  static constants = {
    Aspect: CameraManager.Aspect,
    BarCodeType: CameraManager.BarCodeType,
    Type: CameraManager.Type,
    CaptureMode: CameraManager.CaptureMode,
    CaptureTarget: CameraManager.CaptureTarget,
    CaptureQuality: CameraManager.CaptureQuality,
    Orientation: CameraManager.Orientation,
    FlashMode: CameraManager.FlashMode,
    TorchMode: CameraManager.TorchMode
  };

  static propTypes = {
    ...View.propTypes,
    aspect: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureAudio: PropTypes.bool,
    captureMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureQuality: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureTarget: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    defaultOnFocusComponent: PropTypes.bool,
    flashMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    keepAwake: PropTypes.bool,
    onBarCodeRead: PropTypes.func,
    barcodeScannerEnabled: PropTypes.bool,
    onFocusChanged: PropTypes.func,
    onZoomChanged: PropTypes.func,
    mirrorImage: PropTypes.bool,
    barCodeTypes: PropTypes.array,
    orientation: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    playSoundOnCapture: PropTypes.bool,
    torchMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    type: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ])
  };

  static defaultProps = {
    aspect: CameraManager.Aspect.fill,
    type: CameraManager.Type.back,
    orientation: CameraManager.Orientation.auto,
    captureAudio: false,
    captureMode: CameraManager.CaptureMode.still,
    captureTarget: CameraManager.CaptureTarget.cameraRoll,
    captureQuality: CameraManager.CaptureQuality.high,
    defaultOnFocusComponent: true,
    flashMode: CameraManager.FlashMode.off,
    playSoundOnCapture: true,
    torchMode: CameraManager.TorchMode.off,
    mirrorImage: false,
    barCodeTypes: Object.values(CameraManager.BarCodeType),
  };

  static checkDeviceAuthorizationStatus = CameraManager.checkDeviceAuthorizationStatus;
  static checkVideoAuthorizationStatus = CameraManager.checkVideoAuthorizationStatus;
  static checkAudioAuthorizationStatus = CameraManager.checkAudioAuthorizationStatus;

  setNativeProps(props) {
    this.refs[CAMERA_REF].setNativeProps(props);
  }

  constructor() {
    super();
    this.state = {
      isAuthorized: false,
      isRecording: false
    };
  }

  async componentWillMount() {
    this._addOnBarCodeReadListener()

    let { captureMode } = convertNativeProps({ captureMode: this.props.captureMode })
    let hasVideoAndAudio = this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video
    let check = hasVideoAndAudio ? Camera.checkDeviceAuthorizationStatus : Camera.checkVideoAuthorizationStatus;

    if (check) {
      const isAuthorized = await check();
      this.setState({ isAuthorized });
    }
  }

  componentWillUnmount() {
    this._removeOnBarCodeReadListener()

    if (this.state.isRecording) {
      this.stopCapture();
    }
  }

  componentWillReceiveProps(newProps) {
    const { onBarCodeRead } = this.props
    if (onBarCodeRead && !newProps.onBarCodeRead) {
      this._addOnBarCodeReadListener(newProps)
    }
  }

  _addOnBarCodeReadListener(props) {
    const { onBarCodeRead } = props || this.props
    this._removeOnBarCodeReadListener()
    if (onBarCodeRead) {
      this.cameraBarCodeReadListener = Platform.select({
        ios: NativeAppEventEmitter.addListener('CameraBarCodeRead', this._onBarCodeRead),
        android: DeviceEventEmitter.addListener('CameraBarCodeReadAndroid',  this._onBarCodeRead)
      })
    }
  }
  _removeOnBarCodeReadListener() {
    const listener = this.cameraBarCodeReadListener
    if (listener) {
      listener.remove()
    }
  }

  render() {
    const style = [styles.base, this.props.style];
    const nativeProps = convertNativeProps(this.props);

    return <RCTCamera ref={CAMERA_REF} {...nativeProps} />;
  }

  _onBarCodeRead = (data) => {
    if (this.props.onBarCodeRead) {
      this.props.onBarCodeRead(data)
    }
  };

  capture(options) {
    const props = convertNativeProps(this.props);
    options = {
      audio: props.captureAudio,
      barCodeTypes: props.barCodeTypes,
      mode: props.captureMode,
      playSoundOnCapture: props.playSoundOnCapture,
      target: props.captureTarget,
      quality: props.captureQuality,
      type: props.type,
      title: '',
      description: '',
      mirrorImage: props.mirrorImage,
      ...options
    };

    if (options.mode === Camera.constants.CaptureMode.video) {
      options.totalSeconds = (options.totalSeconds > -1 ? options.totalSeconds : -1);
      options.preferredTimeScale = options.preferredTimeScale || 30;
      this.setState({ isRecording: true });
    }

    return CameraManager.capture(options);
  }

  stopCapture() {
    if (this.state.isRecording) {
      this.setState({ isRecording: false });
      return CameraManager.stopCapture();
    }
    return Promise.resolve("Not Recording.");
  }

  getFOV() {
    return CameraManager.getFOV();
  }

  hasFlash() {
    if (Platform.OS === 'android') {
      const props = convertNativeProps(this.props);
      return CameraManager.hasFlash({
        type: props.type
      });
    }
    return CameraManager.hasFlash();
  }
}

export const constants = Camera.constants;

const RCTCamera = requireNativeComponent('RCTCamera', Camera);

const styles = StyleSheet.create({
  base: {},
});
<commit_msg>Handle string values for captureTarget prop (#543)<commit_after>import React, { Component, PropTypes } from 'react';
import {
  DeviceEventEmitter, // android
  NativeAppEventEmitter, // ios
  NativeModules,
  Platform,
  StyleSheet,
  requireNativeComponent,
  View,
} from 'react-native';

const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule;
const CAMERA_REF = 'camera';

function convertNativeProps(props) {
  const newProps = { ...props };
  if (typeof props.aspect === 'string') {
    newProps.aspect = Camera.constants.Aspect[props.aspect];
  }

  if (typeof props.flashMode === 'string') {
    newProps.flashMode = Camera.constants.FlashMode[props.flashMode];
  }

  if (typeof props.orientation === 'string') {
    newProps.orientation = Camera.constants.Orientation[props.orientation];
  }

  if (typeof props.torchMode === 'string') {
    newProps.torchMode = Camera.constants.TorchMode[props.torchMode];
  }

  if (typeof props.type === 'string') {
    newProps.type = Camera.constants.Type[props.type];
  }

  if (typeof props.captureQuality === 'string') {
    newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality];
  }

  if (typeof props.captureMode === 'string') {
    newProps.captureMode = Camera.constants.CaptureMode[props.captureMode];
  }

  if (typeof props.captureTarget === 'string') {
    newProps.captureTarget = Camera.constants.CaptureTarget[props.captureTarget];
  }

  // do not register barCodeTypes if no barcode listener
  if (typeof props.onBarCodeRead !== 'function') {
    newProps.barCodeTypes = [];
  }

  newProps.barcodeScannerEnabled = typeof props.onBarCodeRead === 'function'

  return newProps;
}

export default class Camera extends Component {

  static constants = {
    Aspect: CameraManager.Aspect,
    BarCodeType: CameraManager.BarCodeType,
    Type: CameraManager.Type,
    CaptureMode: CameraManager.CaptureMode,
    CaptureTarget: CameraManager.CaptureTarget,
    CaptureQuality: CameraManager.CaptureQuality,
    Orientation: CameraManager.Orientation,
    FlashMode: CameraManager.FlashMode,
    TorchMode: CameraManager.TorchMode
  };

  static propTypes = {
    ...View.propTypes,
    aspect: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureAudio: PropTypes.bool,
    captureMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureQuality: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureTarget: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    defaultOnFocusComponent: PropTypes.bool,
    flashMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    keepAwake: PropTypes.bool,
    onBarCodeRead: PropTypes.func,
    barcodeScannerEnabled: PropTypes.bool,
    onFocusChanged: PropTypes.func,
    onZoomChanged: PropTypes.func,
    mirrorImage: PropTypes.bool,
    barCodeTypes: PropTypes.array,
    orientation: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    playSoundOnCapture: PropTypes.bool,
    torchMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    type: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ])
  };

  static defaultProps = {
    aspect: CameraManager.Aspect.fill,
    type: CameraManager.Type.back,
    orientation: CameraManager.Orientation.auto,
    captureAudio: false,
    captureMode: CameraManager.CaptureMode.still,
    captureTarget: CameraManager.CaptureTarget.cameraRoll,
    captureQuality: CameraManager.CaptureQuality.high,
    defaultOnFocusComponent: true,
    flashMode: CameraManager.FlashMode.off,
    playSoundOnCapture: true,
    torchMode: CameraManager.TorchMode.off,
    mirrorImage: false,
    barCodeTypes: Object.values(CameraManager.BarCodeType),
  };

  static checkDeviceAuthorizationStatus = CameraManager.checkDeviceAuthorizationStatus;
  static checkVideoAuthorizationStatus = CameraManager.checkVideoAuthorizationStatus;
  static checkAudioAuthorizationStatus = CameraManager.checkAudioAuthorizationStatus;

  setNativeProps(props) {
    this.refs[CAMERA_REF].setNativeProps(props);
  }

  constructor() {
    super();
    this.state = {
      isAuthorized: false,
      isRecording: false
    };
  }

  async componentWillMount() {
    this._addOnBarCodeReadListener()

    let { captureMode } = convertNativeProps({ captureMode: this.props.captureMode })
    let hasVideoAndAudio = this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video
    let check = hasVideoAndAudio ? Camera.checkDeviceAuthorizationStatus : Camera.checkVideoAuthorizationStatus;

    if (check) {
      const isAuthorized = await check();
      this.setState({ isAuthorized });
    }
  }

  componentWillUnmount() {
    this._removeOnBarCodeReadListener()

    if (this.state.isRecording) {
      this.stopCapture();
    }
  }

  componentWillReceiveProps(newProps) {
    const { onBarCodeRead } = this.props
    if (onBarCodeRead && !newProps.onBarCodeRead) {
      this._addOnBarCodeReadListener(newProps)
    }
  }

  _addOnBarCodeReadListener(props) {
    const { onBarCodeRead } = props || this.props
    this._removeOnBarCodeReadListener()
    if (onBarCodeRead) {
      this.cameraBarCodeReadListener = Platform.select({
        ios: NativeAppEventEmitter.addListener('CameraBarCodeRead', this._onBarCodeRead),
        android: DeviceEventEmitter.addListener('CameraBarCodeReadAndroid',  this._onBarCodeRead)
      })
    }
  }
  _removeOnBarCodeReadListener() {
    const listener = this.cameraBarCodeReadListener
    if (listener) {
      listener.remove()
    }
  }

  render() {
    const style = [styles.base, this.props.style];
    const nativeProps = convertNativeProps(this.props);

    return <RCTCamera ref={CAMERA_REF} {...nativeProps} />;
  }

  _onBarCodeRead = (data) => {
    if (this.props.onBarCodeRead) {
      this.props.onBarCodeRead(data)
    }
  };

  capture(options) {
    const props = convertNativeProps(this.props);
    options = {
      audio: props.captureAudio,
      barCodeTypes: props.barCodeTypes,
      mode: props.captureMode,
      playSoundOnCapture: props.playSoundOnCapture,
      target: props.captureTarget,
      quality: props.captureQuality,
      type: props.type,
      title: '',
      description: '',
      mirrorImage: props.mirrorImage,
      ...options
    };

    if (options.mode === Camera.constants.CaptureMode.video) {
      options.totalSeconds = (options.totalSeconds > -1 ? options.totalSeconds : -1);
      options.preferredTimeScale = options.preferredTimeScale || 30;
      this.setState({ isRecording: true });
    }

    return CameraManager.capture(options);
  }

  stopCapture() {
    if (this.state.isRecording) {
      this.setState({ isRecording: false });
      return CameraManager.stopCapture();
    }
    return Promise.resolve("Not Recording.");
  }

  getFOV() {
    return CameraManager.getFOV();
  }

  hasFlash() {
    if (Platform.OS === 'android') {
      const props = convertNativeProps(this.props);
      return CameraManager.hasFlash({
        type: props.type
      });
    }
    return CameraManager.hasFlash();
  }
}

export const constants = Camera.constants;

const RCTCamera = requireNativeComponent('RCTCamera', Camera);

const styles = StyleSheet.create({
  base: {},
});
<|endoftext|>


<commit_before>'use strict';

// MODULES //

var tape = require( 'tape' );
var round = require( '@stdlib/math/base/special/round' );
var isnan = require( '@stdlib/math/base/utils/is-nan' );
var chi2gof = require( '@stdlib/math/generics/statistics/chi2gof' );
var pmf = require( '@stdlib/math/base/dist/negative-binomial/pmf' ).factory;
var factory = require( './../lib/factory.js' );

// VARIABLES //

var opts = {
	'skip': ( process.env.TEST_MODE === 'coverage' )
};

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof factory, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function returns a pseudorandom number generator (no seed)', function test( t ) {
	var negativeBinomial;
	var r;
	var i;

	// When binding distribution parameters...
	negativeBinomial = factory( 80, 0.05 );
	for ( i = 0; i < 100; i++ ) {
		r = negativeBinomial();
		t.equal( typeof r, 'number', 'returns a number' );
	}

	// Without binding distribution parameters...
	negativeBinomial = factory();
	for ( i = 0; i < 100; i++ ) {
		r = negativeBinomial( 120, 0.75 );
		t.equal( typeof r, 'number', 'returns a number' );
	}

	t.end();
});

tape( 'the function returns a seeded pseudorandom number generator', function test( t ) {
	var negativeBinomial1;
	var negativeBinomial2;
	var seed;
	var r1;
	var r2;
	var i;

	seed = round( Date.now() / 1000 );

	negativeBinomial1 = factory( 20, 0.3, {
		'seed': seed
	});
	negativeBinomial2 = factory( 20, 0.3, {
		'seed': seed
	});

	t.notEqual( negativeBinomial1, negativeBinomial2, 'separate generators' );

	for ( i = 0; i < 100; i++ ) {
		r1 = negativeBinomial1();
		r2 = negativeBinomial2();
		t.equal( r1, r2, 'both return same number' );
	}
	t.end();
});

tape( 'attached to the returned function is the generator name', function test( t ) {
	var negativeBinomial = factory();
	t.equal( negativeBinomial.NAME, 'negative-binomial', 'has `NAME` property' );
	t.end();
});

tape( 'attached to the returned function is the underlying PRNG', function test( t ) {
	var negativeBinomial = factory();
	t.equal( typeof negativeBinomial.PRNG, 'function', 'has `PRNG` property' );
	t.end();
});

tape( 'attached to the returned function is the generator seed', function test( t ) {
	var negativeBinomial = factory({
		'seed': 12345
	});
	t.equal( typeof negativeBinomial.SEED, 'number', 'has `SEED` property' );
	t.equal( negativeBinomial.SEED, 12345, 'equal to provided seed' );
	t.end();
});

tape( 'the function throws an error if provided a number of failures argument which is not a positive number', function test( t ) {
	var values;
	var i;

	values = [
		-1.0,
		-0.5,
		0.0,
		NaN,
		'5',
		null,
		true,
		undefined,
		[],
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( value, 0.5 );
		};
	}
});

tape( 'the function throws an error if provided a success probability argument which is not a number', function test( t ) {
	var values;
	var i;

	values = [
		NaN,
		'5',
		null,
		true,
		undefined,
		[],
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( 10, value );
		};
	}
});

tape( 'the function throws an error if provided a success probability argument which is not a number of the interval `(0,1)`', function test( t ) {
	var values;
	var i;

	values = [
		5,
		3.14,
		1.0,
		0.0,
		-1.0,
		-0.5
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( 10, value );
		};
	}
});

tape( 'the function throws an error if provided an options argument which is not an object (no other arguments)', function test( t ) {
	var values;
	var i;

	values = [
		'abc',
		5,
		NaN,
		null,
		true,
		undefined,
		[],
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( value );
		};
	}
});

tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) {
	var values;
	var i;

	values = [
		'abc',
		5,
		NaN,
		null,
		true,
		undefined,
		[],
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( 10, 0.3, value );
		};
	}
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a first argument which is `NaN`', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();
	r = negativeBinomial( NaN, 0.5 );

	t.strictEqual( isnan( r ), true, 'returns NaN' );
	t.end();
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a second argument which is `NaN`', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();
	r = negativeBinomial( 2, NaN );

	t.strictEqual( isnan( r ), true, 'returns NaN' );
	t.end();
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided `NaNs`', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();
	r = negativeBinomial( NaN, NaN );

	t.strictEqual( isnan( r ), true, 'returns NaN' );
	t.end();
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a second argument which is not between `0` and `1` (exclusive)', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();

	r = negativeBinomial( 2, 3.14 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, -1.0 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, 1.5 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, 0.0 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, 1.0 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	t.end();
});

// FIXME: PMF seems to return incorrect results
opts.skip = true;
tape( 'the function returns a PRNG for generating random numbers from a negative binomial distribution', opts, function test( t ) {
	var negativeBinomial;
	var rejected;
	var repeats;
	var pValue;
	var nbpmf;
	var probs;
	var freq;
	var N;
	var r;
	var p;
	var i;
	var j;
	var x;

	r = 40;
	p = 0.20;
	nbpmf = pmf( r, p );

	freq = new Array( 30 );
	probs = new Array( freq.length );
	for ( j = 0; j < freq.length; j++ ) {
		probs[ j ] = nbpmf( j );
	}
	repeats = 100;
	N = 1e3;
	rejected = 0;
	for ( i = 0; i < repeats; i++ ) {
		negativeBinomial = factory( r, p );
		t.ok( true, 'seed: '+negativeBinomial.SEED );

		// Reset the `freq` array...
		for ( j = 0; j < freq.length; j++ ) {
			freq[ j ] = 0;
		}
		for ( j = 0; j < N; j++ ) {
			x = negativeBinomial();
			freq[ x ] += 1;
		}
		// Test using chi-square goodness-of-fit test:
		pValue = chi2gof( freq, probs, {
			'rescale': true,
			'simulate': true,
			'iterations': 500
		}).pValue;
		t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue );
		if ( pValue < 0.05 ) {
			rejected += 1;
		}
	}
	// Account for small sample sizes and few repeats...
	t.ok( rejected / repeats < 0.15, 'null hypothesis (i.e., that numbers are drawn from NegativeBinomial('+r+','+p+') is rejected in less than 15% of cases ('+rejected+' of '+repeats+')' );
	t.end();
});
<commit_msg>Require that goodness-of-fit tests succeed twice in a row if the first run fails<commit_after>'use strict';

// MODULES //

var tape = require( 'tape' );
var round = require( '@stdlib/math/base/special/round' );
var isnan = require( '@stdlib/math/base/utils/is-nan' );
var chi2gof = require( '@stdlib/math/generics/statistics/chi2gof' );
var pmf = require( '@stdlib/math/base/dist/negative-binomial/pmf' ).factory;
var factory = require( './../lib/factory.js' );

// VARIABLES //

var opts = {
	'skip': ( process.env.TEST_MODE === 'coverage' )
};

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof factory, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function returns a pseudorandom number generator (no seed)', function test( t ) {
	var negativeBinomial;
	var r;
	var i;

	// When binding distribution parameters...
	negativeBinomial = factory( 80, 0.05 );
	for ( i = 0; i < 100; i++ ) {
		r = negativeBinomial();
		t.equal( typeof r, 'number', 'returns a number' );
	}

	// Without binding distribution parameters...
	negativeBinomial = factory();
	for ( i = 0; i < 100; i++ ) {
		r = negativeBinomial( 120, 0.75 );
		t.equal( typeof r, 'number', 'returns a number' );
	}

	t.end();
});

tape( 'the function returns a seeded pseudorandom number generator', function test( t ) {
	var negativeBinomial1;
	var negativeBinomial2;
	var seed;
	var r1;
	var r2;
	var i;

	seed = round( Date.now() / 1000 );

	negativeBinomial1 = factory( 20, 0.3, {
		'seed': seed
	});
	negativeBinomial2 = factory( 20, 0.3, {
		'seed': seed
	});

	t.notEqual( negativeBinomial1, negativeBinomial2, 'separate generators' );

	for ( i = 0; i < 100; i++ ) {
		r1 = negativeBinomial1();
		r2 = negativeBinomial2();
		t.equal( r1, r2, 'both return same number' );
	}
	t.end();
});

tape( 'attached to the returned function is the generator name', function test( t ) {
	var negativeBinomial = factory();
	t.equal( negativeBinomial.NAME, 'negative-binomial', 'has `NAME` property' );
	t.end();
});

tape( 'attached to the returned function is the underlying PRNG', function test( t ) {
	var negativeBinomial = factory();
	t.equal( typeof negativeBinomial.PRNG, 'function', 'has `PRNG` property' );
	t.end();
});

tape( 'attached to the returned function is the generator seed', function test( t ) {
	var negativeBinomial = factory({
		'seed': 12345
	});
	t.equal( typeof negativeBinomial.SEED, 'number', 'has `SEED` property' );
	t.equal( negativeBinomial.SEED, 12345, 'equal to provided seed' );
	t.end();
});

tape( 'the function throws an error if provided a number of failures argument which is not a positive number', function test( t ) {
	var values;
	var i;

	values = [
		-1.0,
		-0.5,
		0.0,
		NaN,
		'5',
		null,
		true,
		undefined,
		[],
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( value, 0.5 );
		};
	}
});

tape( 'the function throws an error if provided a success probability argument which is not a number', function test( t ) {
	var values;
	var i;

	values = [
		NaN,
		'5',
		null,
		true,
		undefined,
		[],
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( 10, value );
		};
	}
});

tape( 'the function throws an error if provided a success probability argument which is not a number of the interval `(0,1)`', function test( t ) {
	var values;
	var i;

	values = [
		5,
		3.14,
		1.0,
		0.0,
		-1.0,
		-0.5
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( 10, value );
		};
	}
});

tape( 'the function throws an error if provided an options argument which is not an object (no other arguments)', function test( t ) {
	var values;
	var i;

	values = [
		'abc',
		5,
		NaN,
		null,
		true,
		undefined,
		[],
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( value );
		};
	}
});

tape( 'the function throws an error if provided an options argument which is not an object (other arguments)', function test( t ) {
	var values;
	var i;

	values = [
		'abc',
		5,
		NaN,
		null,
		true,
		undefined,
		[],
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function() {
			factory( 10, 0.3, value );
		};
	}
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a first argument which is `NaN`', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();
	r = negativeBinomial( NaN, 0.5 );

	t.strictEqual( isnan( r ), true, 'returns NaN' );
	t.end();
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a second argument which is `NaN`', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();
	r = negativeBinomial( 2, NaN );

	t.strictEqual( isnan( r ), true, 'returns NaN' );
	t.end();
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided `NaNs`', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();
	r = negativeBinomial( NaN, NaN );

	t.strictEqual( isnan( r ), true, 'returns NaN' );
	t.end();
});

tape( 'when called without arguments, the function returns a PRNG that returns `NaN` if provided a second argument which is not between `0` and `1` (exclusive)', function test( t ) {
	var negativeBinomial;
	var r;

	negativeBinomial = factory();

	r = negativeBinomial( 2, 3.14 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, -1.0 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, 1.5 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, 0.0 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	r = negativeBinomial( 2, 1.0 );
	t.strictEqual( isnan( r ), true, 'returns NaN' );

	t.end();
});

// FIXME: PMF seems to return incorrect results
opts.skip = true;
tape( 'the function returns a PRNG for generating random numbers from a negative binomial distribution', opts, function test( t ) {
	var threshold;
	var repeats;
	var count;
	var npass;
	var nbpmf;
	var probs;
	var freq;
	var N;
	var r;
	var p;
	var j;
	var x;

	threshold = 0.15;

	r = 40;
	p = 0.20;
	nbpmf = pmf( r, p );

	freq = new Array( 30 );
	probs = new Array( freq.length );
	for ( j = 0; j < freq.length; j++ ) {
		probs[ j ] = nbpmf( j );
	}
	repeats = 100;
	N = 1e3;

	count = -1;
	npass = 0;

	gof();

	function gof() {
		var negativeBinomial;
		var rejected;
		var pValue;
		var bool;
		var i;
		var j;

		count += 1;
		rejected = 0;
		for ( i = 0; i < repeats; i++ ) {
			negativeBinomial = factory( r, p );
			t.ok( true, 'seed: '+negativeBinomial.SEED );

			// Reset the `freq` array...
			for ( j = 0; j < freq.length; j++ ) {
				freq[ j ] = 0;
			}
			for ( j = 0; j < N; j++ ) {
				x = negativeBinomial();
				freq[ x ] += 1;
			}
			// Test using chi-square goodness-of-fit test:
			pValue = chi2gof( freq, probs, {
				'rescale': true,
				'simulate': true,
				'iterations': 500
			}).pValue;
			t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue );
			if ( pValue < 0.05 ) {
				rejected += 1;
			}
		}
		// Account for small sample sizes and few repeats...
		bool = ( rejected / repeats < threshold );

		// If we succeed the first time, we are done...
		if ( count === 0 && bool ) {
			return done( bool, rejected );
		}
		// Retry mode...
		if ( bool ) {
			npass += 1;
		}
		// Retry twice...
		if ( count < 2 ) {
			return gof();
		}
		// Both retries must succeed for test to pass:
		bool = ( npass >= 2 );
		return done( bool, rejected );
	}

	function done( bool, rejected ) {
		t.ok( bool, 'null hypothesis (i.e., that numbers are drawn from NegativeBinomial('+r+','+p+') is rejected in less than '+(threshold*100)+'% of cases ('+rejected+' of '+repeats+'). Repeats: '+npass+' of '+count+'.' );
		t.end();
	}
});
<|endoftext|>


<commit_before>// ID or URL of the Hosted Web App plugin - THIS SETTING WILL NEED TO BE UPDATED IF THE PLUGIN IS RELOCATED
var pluginIdOrUrl = 'https://github.com/manifoldjs/ManifoldCordova.git';

var manifestTools = require('./tools'),
    path = require('path'),
    url = require('url'),
    exec = require('child_process').exec,
    fs = require('fs'),
    log = require('loglevel'),
    validations = require('./validations'),
    downloader = require('./downloader'),
    Q = require('q'),
    mkdirp = require('mkdirp');

var createApps = function (w3cManifestInfo, rootDir, platforms, build, callback) {

  // determine the path where the Cordova app will be created
  var appName = w3cManifestInfo.content.short_name;
  var generatedAppDir = path.join(rootDir, appName);

  // create app directory
  mkdirp(generatedAppDir, function (err) {
    if (err && err.code !== 'EEXIST') {
      return callback(err);
    }

    // process all requested platforms
    var pendingTasks = [];
    var cordovaPlatforms = [];
    platforms.forEach(function (el) {
      var platform = el.toUpperCase();
      if (platform === 'CHROME') {
        pendingTasks.push(createChromeApp(w3cManifestInfo, generatedAppDir, build));
      } else if (platform === 'FIREFOX') {
        pendingTasks.push(createFirefoxApp(w3cManifestInfo, generatedAppDir, build));
      } else if (platform === 'WINDOWS' || platform === 'IOS' || platform === 'ANDROID') {
        // all these platforms are handled by Cordova
        cordovaPlatforms.push(el);
      } else {
        return callback(new Error('Unknown platform \'' + el + '\' specified.'));
      }
    });

    // generate Cordova project
    if (cordovaPlatforms.length) {
      pendingTasks.push(createCordovaApp(w3cManifestInfo, generatedAppDir, cordovaPlatforms, build));
    }

    Q.allSettled(pendingTasks)
      .done(function (results) {
        var err;
        results.forEach(function (task) {
          if (task.state !== 'fulfilled') {
            log.error('WARNING: ' + task.reason.message);
            if (!err) {
              err = new Error('One or more errors occurred when generating the application.');
            }
          }
        });

        if (callback) {
          callback(err);
        }
      });
  });
};

var createChromeApp = function (w3cManifestInfo, generatedAppDir, build) {
  log.info('Generating the Chrome application...');

  var task = Q.defer();

  manifestTools.convertTo(w3cManifestInfo, 'chromeOS', function (err, chromeManifestInfo) {

    if (err) {
      log.error(err.message);
      return task.reject(new Error('The Chrome project could not be created successfully.'));
    }

    // if the platform dir doesn't exist, create it
    var platformDir = path.join(generatedAppDir, 'chrome');
    mkdirp(platformDir, function (err) {
      if (err && err.code !== 'EEXIST') {
        log.error(err.message);
        return task.reject(new Error('The Chrome project could not be created successfully.'));
      }

      // download icons to the app's folder
      var pendingDownloads = [];
      log.info('Downloading Chrome icons...');
      var icons = chromeManifestInfo.content.icons;
      for (var size in icons) {
        var downloadTask = new Q.defer();
        pendingDownloads.push(downloadTask.promise);
        var iconUrl = url.resolve(w3cManifestInfo.content.start_url, icons[size]);
        downloader.downloadImage(iconUrl, platformDir, function (err, data) {
          if (err) {
            log.warn('WARNING: Failed to download icon file: ' + icons[size] + ' (' + err.message + ')');
            log.debug(err);
          } else {
            var localPath = path.basename(data.path);
            icons[size] = localPath;
          }

          downloadTask.resolve();
        });
      }

      // copy the manifest file to the app folder
      Q.allSettled(pendingDownloads)
        .done(function () {
          log.info('Copying the Chrome manifest to the app folder...');
          var manifestFilePath = path.join(platformDir, 'manifest.json');
          manifestTools.writeToFile(chromeManifestInfo, manifestFilePath, function (err) {
            if (err) {
              log.error('ERROR: Failed to copy the manifest to the Chrome platform folder.');
              log.debug(err);
              return task.reject(new Error('The Chrome project could not be created successfully.'));
            }

            return task.resolve();
          });
        });
    });
  });

  return task.promise;
};

var createFirefoxApp = function (w3cManifestInfo, generatedAppDir, build) {
  log.info('Generating the Firefox application...');

  var task = Q.defer();

  manifestTools.convertTo(w3cManifestInfo, 'firefox', function (err, firefoxManifestInfo) {
    if (err) {
      log.error(err.message);
      return task.reject(new Error('The Firefox project could not be created successfully.'));
    }

    // if the platform dir doesn't exist, create it
    var platformDir = path.join(generatedAppDir, 'firefox');
    mkdirp(platformDir, function (err) {
      if (err && err.code !== 'EEXIST') {
        log.error(err.message);
        return task.reject(new Error('The Firefox project could not be created successfully.'));
      }

      // copy the manifest file to the app folder
      log.info('Copying the Firefox manifest to the app folder...');
      var manifestFilePath = path.join(platformDir, 'manifest.webapp');
      manifestTools.writeToFile(firefoxManifestInfo, manifestFilePath, function (err) {
        if (err) {
          log.error('ERROR: Failed to copy the manifest to the Firefox platform folder.');
          log.debug(err);
          return task.reject(new Error('The Firefox project could not be created successfully.'));
        }

        return task.resolve();
      });
    });
  });

  return task.promise;
};

var createCordovaApp = function (w3cManifestInfo, generatedAppDir, platforms, build) {
  log.info('Generating the Cordova application...');

  var task = Q.defer();

  // path to cordova shell command
  var cordovaPath = path.resolve(__dirname, '..', 'node_modules', 'cordova', 'bin', 'cordova');

  // go to the directory where the app will be created
  process.chdir(generatedAppDir);

  // generate a reverse-domain-style package name from the manifest's start_url
  var packageName = '';
  url.parse(w3cManifestInfo.content.start_url)
            .hostname
            .replace(/-/g, '')
            .split('.')
            .map(function (segment) {
              packageName = segment + (packageName ? '.' : '') + packageName;
            });

  // create the Cordova project
  log.info('Creating the Cordova project...');
  var cmdLine = cordovaPath + ' create cordova ' + packageName + ' ' + w3cManifestInfo.content.short_name;
  log.debug('    ' + cmdLine);
  exec(cmdLine, function (err, stdout, stderr) {

    log.debug(stdout);
    if (err) {
      log.error('ERROR: Failed to create the Cordova application.');
      log.debug(err);
      return task.reject(new Error('The Cordova project could not be created successfully.\n' + err.message));
    } else if (stderr.length) {
      log.error(stderr.trim());
    }

    // copy the manifest file to the 'www' folder of the app
    log.info('Copying the W3C manifest to the Cordova app folder...');
    var platformDir = path.join(generatedAppDir, 'cordova');
    var manifestFilePath = path.join(platformDir, 'manifest.json');
    manifestTools.writeToFile(w3cManifestInfo, manifestFilePath, function (err) {

      log.debug(stdout);
      if (err) {
        log.error('ERROR: Failed to copy the manifest to the app folder.');
        log.debug(err);
        return task.reject(new Error('The Cordova project could not be created successfully.'));
      }

      // set generated app's directory as current
      process.chdir(platformDir);

      // add the Hosted Web App plugin
      log.info('Adding the Hosted Web App plugin to the Cordova project...');
      cmdLine = cordovaPath + ' plugin add ' + pluginIdOrUrl;
      log.debug('    ' + cmdLine);
      exec(cmdLine, function (err, stdout, stderr) {

        log.debug(stdout);
        if (err) {
          log.error('ERROR: Failed to add the Hosted Web App plugin to the Cordova project.');
          log.debug(err);
          return task.reject(new Error('The Cordova project could not be created successfully.'));
        } else if (stderr.length) {
          log.error(stderr.trim());
        }

        // process all the specified platforms
        var pendingTasks = [];
        platforms.forEach(function (platform, index) {
          log.info('Adding Cordova platform: ' + platform + '...');

          var platformTask = new Q.defer();
          pendingTasks.push(platformTask.promise);
          cmdLine = cordovaPath + ' platform add ' + platform;
          log.debug('    ' + cmdLine);
          exec(cmdLine, function (err, stdout, stderr) {

            log.debug(stdout);
            if (err) {
              log.warn('WARNING: Failed to add ' + platform + ' platform.');
              log.debug(err);
              return platformTask.reject(err);
            } else if (stderr.length) {
              log.error(stderr.trim());
            }

            log.info('Creating shortcut for platform: ' + platform + '...');
            createPlatformShortcut(generatedAppDir, platform, function (err) {

              log.debug(stdout);
              if (err) {
                log.warn('WARNING: Failed to create shortcut for platform: ' + platform + '.');
                log.debug(err);
              }

              // build the platform-specific projects
              if (build) {
                log.info('Building Cordova platform: ' + platform + '...');
                cmdLine = cordovaPath + ' build ' + platform;
                log.debug('    ' + cmdLine);
                exec(cmdLine, function (err, stdout, stderr) {

                  log.debug(stdout);
                  if (err) {
                    log.warn('WARNING: Failed to build platform: ' + platform + '.');
                    log.debug(err);
                    return platformTask.reject(err);
                  } else if (stderr.length) {
                    log.error(stderr.trim());
                  }

                  platformTask.resolve();
                });
              } else {
                platformTask.resolve();
              }
            });
          });
        });

        Q.allSettled(pendingTasks)
          .done(function (results) {
            var err;
            if (results.some(function (platformTask) { return platformTask.state !== 'fulfilled'; })) {
              return task.reject(new Error('One or more tasks failed while generating the Cordova application.'))
            } else {
              return task.resolve();
            }
          });
      });
    });
  });

  return task.promise;
};

var createPlatformShortcut = function (projectPath, platform, callback) {
  var srcpath = path.resolve(projectPath, 'cordova', 'platforms', platform);
  var dstpath = path.resolve(projectPath, platform);
  fs.symlink(srcpath, dstpath, 'junction', function (err) {
    if (callback) {
      callback(err);
    }
  });
};

module.exports = {
  createApps: createApps,
  createChromeApp: createChromeApp,
  createFirefoxApp: createFirefoxApp,
  createCordovaApp: createCordovaApp
};
<commit_msg>Updated log message<commit_after>// ID or URL of the Hosted Web App plugin - THIS SETTING WILL NEED TO BE UPDATED IF THE PLUGIN IS RELOCATED
var pluginIdOrUrl = 'https://github.com/manifoldjs/ManifoldCordova.git';

var manifestTools = require('./tools'),
    path = require('path'),
    url = require('url'),
    exec = require('child_process').exec,
    fs = require('fs'),
    log = require('loglevel'),
    validations = require('./validations'),
    downloader = require('./downloader'),
    Q = require('q'),
    mkdirp = require('mkdirp');

var createApps = function (w3cManifestInfo, rootDir, platforms, build, callback) {

  // determine the path where the Cordova app will be created
  var appName = w3cManifestInfo.content.short_name;
  var generatedAppDir = path.join(rootDir, appName);

  // create app directory
  mkdirp(generatedAppDir, function (err) {
    if (err && err.code !== 'EEXIST') {
      return callback(err);
    }

    // process all requested platforms
    var pendingTasks = [];
    var cordovaPlatforms = [];
    platforms.forEach(function (el) {
      var platform = el.toUpperCase();
      if (platform === 'CHROME') {
        pendingTasks.push(createChromeApp(w3cManifestInfo, generatedAppDir, build));
      } else if (platform === 'FIREFOX') {
        pendingTasks.push(createFirefoxApp(w3cManifestInfo, generatedAppDir, build));
      } else if (platform === 'WINDOWS' || platform === 'IOS' || platform === 'ANDROID') {
        // all these platforms are handled by Cordova
        cordovaPlatforms.push(el);
      } else {
        return callback(new Error('Unknown platform \'' + el + '\' specified.'));
      }
    });

    // generate Cordova project
    if (cordovaPlatforms.length) {
      pendingTasks.push(createCordovaApp(w3cManifestInfo, generatedAppDir, cordovaPlatforms, build));
    }

    Q.allSettled(pendingTasks)
      .done(function (results) {
        var err;
        results.forEach(function (task) {
          if (task.state !== 'fulfilled') {
            log.error('WARNING: ' + task.reason.message);
            if (!err) {
              err = new Error('One or more errors occurred when generating the application.');
            }
          }
        });

        if (callback) {
          callback(err);
        }
      });
  });
};

var createChromeApp = function (w3cManifestInfo, generatedAppDir, build) {
  log.info('Generating the Chrome application...');

  var task = Q.defer();

  manifestTools.convertTo(w3cManifestInfo, 'chromeOS', function (err, chromeManifestInfo) {

    if (err) {
      log.error(err.message);
      return task.reject(new Error('The Chrome project could not be created successfully.'));
    }

    // if the platform dir doesn't exist, create it
    var platformDir = path.join(generatedAppDir, 'chrome');
    mkdirp(platformDir, function (err) {
      if (err && err.code !== 'EEXIST') {
        log.error(err.message);
        return task.reject(new Error('The Chrome project could not be created successfully.'));
      }

      // download icons to the app's folder
      var pendingDownloads = [];
      log.info('Downloading Chrome icons...');
      var icons = chromeManifestInfo.content.icons;
      for (var size in icons) {
        var downloadTask = new Q.defer();
        pendingDownloads.push(downloadTask.promise);
        var iconUrl = url.resolve(w3cManifestInfo.content.start_url, icons[size]);
        downloader.downloadImage(iconUrl, platformDir, function (err, data) {
          if (err) {
            log.warn('WARNING: Failed to download icon file: ' + icons[size] + ' (' + err.message + ')');
            log.debug(err);
          } else {
            var localPath = path.basename(data.path);
            icons[size] = localPath;
          }

          downloadTask.resolve();
        });
      }

      // copy the manifest file to the app folder
      Q.allSettled(pendingDownloads)
        .done(function () {
          log.info('Copying the Chrome manifest to the app folder...');
          var manifestFilePath = path.join(platformDir, 'manifest.json');
          manifestTools.writeToFile(chromeManifestInfo, manifestFilePath, function (err) {
            if (err) {
              log.error('ERROR: Failed to copy the manifest to the Chrome platform folder.');
              log.debug(err);
              return task.reject(new Error('The Chrome project could not be created successfully.'));
            }

            return task.resolve();
          });
        });
    });
  });

  return task.promise;
};

var createFirefoxApp = function (w3cManifestInfo, generatedAppDir, build) {
  log.info('Generating the Firefox application...');

  var task = Q.defer();

  manifestTools.convertTo(w3cManifestInfo, 'firefox', function (err, firefoxManifestInfo) {
    if (err) {
      log.error(err.message);
      return task.reject(new Error('The Firefox project could not be created successfully.'));
    }

    // if the platform dir doesn't exist, create it
    var platformDir = path.join(generatedAppDir, 'firefox');
    mkdirp(platformDir, function (err) {
      if (err && err.code !== 'EEXIST') {
        log.error(err.message);
        return task.reject(new Error('The Firefox project could not be created successfully.'));
      }

      // copy the manifest file to the app folder
      log.info('Copying the Firefox manifest to the app folder...');
      var manifestFilePath = path.join(platformDir, 'manifest.webapp');
      manifestTools.writeToFile(firefoxManifestInfo, manifestFilePath, function (err) {
        if (err) {
          log.error('ERROR: Failed to copy the manifest to the Firefox platform folder.');
          log.debug(err);
          return task.reject(new Error('The Firefox project could not be created successfully.'));
        }

        return task.resolve();
      });
    });
  });

  return task.promise;
};

var createCordovaApp = function (w3cManifestInfo, generatedAppDir, platforms, build) {
  log.info('Generating the Cordova application...');

  var task = Q.defer();

  // path to cordova shell command
  var cordovaPath = path.resolve(__dirname, '..', 'node_modules', 'cordova', 'bin', 'cordova');

  // go to the directory where the app will be created
  process.chdir(generatedAppDir);

  // generate a reverse-domain-style package name from the manifest's start_url
  var packageName = '';
  url.parse(w3cManifestInfo.content.start_url)
            .hostname
            .replace(/-/g, '')
            .split('.')
            .map(function (segment) {
              packageName = segment + (packageName ? '.' : '') + packageName;
            });

  // create the Cordova project
  log.info('Creating the Cordova project...');
  var cmdLine = cordovaPath + ' create cordova ' + packageName + ' ' + w3cManifestInfo.content.short_name;
  log.debug('    ' + cmdLine);
  exec(cmdLine, function (err, stdout, stderr) {

    log.debug(stdout);
    if (err) {
      log.error('ERROR: Failed to create the Cordova application.');
      log.debug(err);
      return task.reject(new Error('The Cordova project could not be created successfully.\n' + err.message));
    } else if (stderr.length) {
      log.error(stderr.trim());
    }

    // copy the manifest file to the app folder
    log.info('Copying the W3C manifest to the app folder...');
    var platformDir = path.join(generatedAppDir, 'cordova');
    var manifestFilePath = path.join(platformDir, 'manifest.json');
    manifestTools.writeToFile(w3cManifestInfo, manifestFilePath, function (err) {

      log.debug(stdout);
      if (err) {
        log.error('ERROR: Failed to copy the manifest to the app folder.');
        log.debug(err);
        return task.reject(new Error('The Cordova project could not be created successfully.'));
      }

      // set generated app's directory as current
      process.chdir(platformDir);

      // add the Hosted Web App plugin
      log.info('Adding the Hosted Web App plugin to the Cordova project...');
      cmdLine = cordovaPath + ' plugin add ' + pluginIdOrUrl;
      log.debug('    ' + cmdLine);
      exec(cmdLine, function (err, stdout, stderr) {

        log.debug(stdout);
        if (err) {
          log.error('ERROR: Failed to add the Hosted Web App plugin to the Cordova project.');
          log.debug(err);
          return task.reject(new Error('The Cordova project could not be created successfully.'));
        } else if (stderr.length) {
          log.error(stderr.trim());
        }

        // process all the specified platforms
        var pendingTasks = [];
        platforms.forEach(function (platform, index) {
          log.info('Adding Cordova platform: ' + platform + '...');

          var platformTask = new Q.defer();
          pendingTasks.push(platformTask.promise);
          cmdLine = cordovaPath + ' platform add ' + platform;
          log.debug('    ' + cmdLine);
          exec(cmdLine, function (err, stdout, stderr) {

            log.debug(stdout);
            if (err) {
              log.warn('WARNING: Failed to add ' + platform + ' platform.');
              log.debug(err);
              return platformTask.reject(err);
            } else if (stderr.length) {
              log.error(stderr.trim());
            }

            log.info('Creating shortcut for platform: ' + platform + '...');
            createPlatformShortcut(generatedAppDir, platform, function (err) {

              log.debug(stdout);
              if (err) {
                log.warn('WARNING: Failed to create shortcut for platform: ' + platform + '.');
                log.debug(err);
              }

              // build the platform-specific projects
              if (build) {
                log.info('Building Cordova platform: ' + platform + '...');
                cmdLine = cordovaPath + ' build ' + platform;
                log.debug('    ' + cmdLine);
                exec(cmdLine, function (err, stdout, stderr) {

                  log.debug(stdout);
                  if (err) {
                    log.warn('WARNING: Failed to build platform: ' + platform + '.');
                    log.debug(err);
                    return platformTask.reject(err);
                  } else if (stderr.length) {
                    log.error(stderr.trim());
                  }

                  platformTask.resolve();
                });
              } else {
                platformTask.resolve();
              }
            });
          });
        });

        Q.allSettled(pendingTasks)
          .done(function (results) {
            var err;
            if (results.some(function (platformTask) { return platformTask.state !== 'fulfilled'; })) {
              return task.reject(new Error('One or more tasks failed while generating the Cordova application.'))
            } else {
              return task.resolve();
            }
          });
      });
    });
  });

  return task.promise;
};

var createPlatformShortcut = function (projectPath, platform, callback) {
  var srcpath = path.resolve(projectPath, 'cordova', 'platforms', platform);
  var dstpath = path.resolve(projectPath, platform);
  fs.symlink(srcpath, dstpath, 'junction', function (err) {
    if (callback) {
      callback(err);
    }
  });
};

module.exports = {
  createApps: createApps,
  createChromeApp: createChromeApp,
  createFirefoxApp: createFirefoxApp,
  createCordovaApp: createCordovaApp
};
<|endoftext|>


<commit_before>var express = require('express')
var app     = express()

app.set('port', (process.env.PORT || 5000))
app.use(express.static(__dirname + '/public'))

app.get('/', function(request, response) {
    response.send('Hello World!')
});

app.get('/webhook', function(req, res) {
    if (req.query['hub.mode'] === 'subscribe' && req.query['hub.verify_token'] === "nP4WrAQsuePDGGsgbxijiAEfka") {
        console.log("Validating webhook");
        res.status(200).send(req.query['hub.challenge']);
    } else {
        console.error("Failed validation. Make sure the validation tokens match.");
        res.sendStatus(403);
    }
});

app.listen(app.get('port'), function() {
    console.log("Node app is running at localhost:" + app.get('port'))
})
<commit_msg>- Barebone communication functions<commit_after>var express = require('express')
var app     = express();

app.set('port', (process.env.PORT || 5000))
app.use(express.static(__dirname + '/public'))

app.get('/', function(request, response) {
    response.send('Hello World!')
});

app.get('/webhook', function(req, res) {
    var data = req.body;

    // Make sure this is a page subscription
    if(data.object === 'page'){
        // Iterate over each entries - there may be multiple if batched
        data.entry.forEach(function(entry){
            var pageID = entry.id;
            var timeOfEvent = entry.time;

            // Iterate over each messaging event
            entry.messaging.forEach(function(event){
                if(event.message){
                    receivedMessage(event);
                }else{
                    console.log("Webhook received unknown event: ", event);
                }
            });
        });

        res.sendStatus(200);
    }
});

function receivedMessage(event){
    var senderID      = event.sender.id;
    var recipientID   = event.recipient.id;
    var timeOfMessage = event.timestamp;
    var message       = event.message;

    console.log("Received message for user %d and page %d at %d with message:", senderID, recipientID, timeOfMessage);
    console.log(JSON.stringify(message));

    var messageId          = message.mid;
    var messageText        = message.text;
    var messageAttachments = message.attachments;

    if(messageText){
        // If we receive a text message, check to see if it matches a keyword
        // and send back the example. Otherwise, just echo the text we received.
        switch(messageText){
            case 'generic':
                sendGenericMessage(senderID);
            break;

            default:
                sendTextMessage(senderID, messageText);
        }
    }else if(messageAttachments){
        sendTextMessage(senderID, "Message with attachment received");
    }
}

function sendGenericMessage(recipientId, messageText){
    // To be expanded in later sections
}

function sendTextMessage(recipientId, messageText){
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            text: messageText
        }
    };

    callSendAPI(messageData);
}

function callSendAPI(messageData){
    request({
        uri: 'https://graph.facebook.com/v2.6/me/messages',
        qs: { access_token: process.env.PAGE_ACCESS_TOKEN },
        method: 'POST',
        json: messageData

    }, function (error, response, body){
        if(!error && response.statusCode == 200){
            var recipientId = body.recipient_id;
            var messageId   = body.message_id;

            console.log("Successfully sent generic message with id %s to recipient %s", messageId, recipientId);
        }else{
            console.error("Unable to send message.");
            console.error(response);
            console.error(error);
        }
    });
}

app.listen(app.get('port'), function() {
    console.log("Node app is running at localhost:" + app.get('port'))
})
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const Twig = require('twig')

const twigRender = Twig.twig

exports.name = 'twig'
exports.outputFormat = 'html'

exports.compile = function (str, options) {
  // Construct the Twig options.
  options = options || {}
  options.data = str
  if ('filename' in options && !('path' in options)) {
    options.path = options.filename
  }

  // Make sure path is always a string, and not an object.
  // TODO: Make sure the `root` is correct?
  if (options.path && typeof options.path !== 'string') {
    const pathRoot = options.root || options.path.root
    if (pathRoot) {
      options.path = path.join(pathRoot, path.format(options.path))
    } else {
      options.path = path.format(options.path)
    }
  }

  // Extend Filters and Functions
  const extendable = {
    filters: 'extendFilter',
    functions: 'extendFunction'
  }
  // eslint-disable-next-line guard-for-in
  for (const extendableName in extendable) {
    const extendFunctionName = extendable[extendableName]
    // Allow options.filters to be a require() string.
    if (typeof options[extendableName] === 'string') {
      try {
        // eslint-disable-next-line import/no-dynamic-require
        options[extendableName] = require(options[extendableName])
      } catch (error) {
        // Ignore
      }
    }
    // Loop through all the given filters.
    for (const name in options[extendableName] || {}) {
      if ({}.hasOwnProperty.call(options[extendableName], name)) {
        switch (typeof options[extendableName][name]) {
          case 'string':
            try {
              // Load the filter module.
              // eslint-disable-next-line import/no-dynamic-require
              const out = require(options[extendableName][name])

              // Check if the module is just a function.
              if (typeof out === 'function') {
                Twig[extendFunctionName](name, out)
              } else if (out && (typeof out === 'object')) {
                // Perhaps it is an associative array of functions?
                for (const outName in out) {
                  if (typeof out[outName] === 'function') {
                    Twig[extendFunctionName](outName, out[outName])
                  }
                }
              }
            } catch (error) {
              // Ignore
            }
            break
          case 'function':
          default:
            Twig[extendFunctionName](name, options[extendableName][name])
            break
        }
      }
    }
  }

  // Build the template.
  let output = ''
  try {
    // Build the template renderer.
    const template = twigRender(options)

    // Use .bind() so that the template is "this" when rendering.
    output = template.render.bind(template)
  } catch (error) {
    console.log(options)
    console.error(error)
  }

  return output
}
<commit_msg>Fix xo<commit_after>'use strict'

const path = require('path')
const Twig = require('twig')

const twigRender = Twig.twig

exports.name = 'twig'
exports.outputFormat = 'html'

exports.compile = function (str, options) {
  // Construct the Twig options.
  options = options || {}
  options.data = str
  if ('filename' in options && !('path' in options)) {
    options.path = options.filename
  }

  // Make sure path is always a string, and not an object.
  // TODO: Make sure the `root` is correct?
  if (options.path && typeof options.path !== 'string') {
    const pathRoot = options.root || options.path.root
    if (pathRoot) {
      options.path = path.join(pathRoot, path.format(options.path))
    } else {
      options.path = path.format(options.path)
    }
  }

  // Extend Filters and Functions
  const extendable = {
    filters: 'extendFilter',
    functions: 'extendFunction'
  }
  // eslint-disable-next-line guard-for-in
  for (const extendableName in extendable) {
    const extendFunctionName = extendable[extendableName]
    // Allow options.filters to be a require() string.
    if (typeof options[extendableName] === 'string') {
      try {
        options[extendableName] = require(options[extendableName])
      } catch (error) {
        // Ignore
      }
    }

    // Loop through all the given filters.
    for (const name in options[extendableName] || {}) {
      if ({}.hasOwnProperty.call(options[extendableName], name)) {
        switch (typeof options[extendableName][name]) {
          case 'string':
            try {
              // Load the filter module.
              const out = require(options[extendableName][name])

              // Check if the module is just a function.
              if (typeof out === 'function') {
                Twig[extendFunctionName](name, out)
              } else if (out && (typeof out === 'object')) {
                // Perhaps it is an associative array of functions?
                for (const outName in out) {
                  if (typeof out[outName] === 'function') {
                    Twig[extendFunctionName](outName, out[outName])
                  }
                }
              }
            } catch (error) {
              // Ignore
            }

            break
          case 'function':
          default:
            Twig[extendFunctionName](name, options[extendableName][name])
            break
        }
      }
    }
  }

  // Build the template.
  let output = ''
  try {
    // Build the template renderer.
    const template = twigRender(options)

    // Use .bind() so that the template is "this" when rendering.
    output = template.render.bind(template)
  } catch (error) {
    console.log(options)
    console.error(error)
  }

  return output
}
<|endoftext|>