<commit_before>'use strict';

const nabuExtractor = require ('nabu-extractor');

/*
 * Inspired by the work of Yahoo for babel-plugin-react-intl.
 */

const COMPONENT_NAMES = [
  'T'
];
const DESCRIPTOR_PROPS = new Set (['msgid', 'desc']);

module.exports = function () {
  function getModuleSourceName (opts) {
    return opts.moduleSourceName || 'react-nabu';
  }

  function getTkey (path) {
    if (path.isIdentifier () || path.isJSXIdentifier ()) {
      return path.node.name;
    }

    let evaluated = path.evaluate ();
    if (evaluated.confident) {
      return evaluated.value;
    }

    throw path.buildCodeFrameError ('[T] msgid must be statically evaluate-able for extraction.');
  }

  function getTvalue (path) {
    if (path.isJSXExpressionContainer ()) {
      path = path.get ('expression');
    }

    let evaluated = path.evaluate ();
    if (evaluated.confident) {
      return evaluated.value;
    }

    throw path.buildCodeFrameError ('[T] msgid must be statically evaluate-able for extraction.');
  }

  function createTdescriptor (propPaths, options) {
    if (!options) {
      options = {};
    }
    const isJSXSource = options.isJSXSource || false;

    return propPaths.reduce ((hash, arr) => {
      let keyPath   = arr[0];
      let valuePath = arr[1];
      let locPath   = arr[2];

      let key = getTkey (keyPath);

      if (!DESCRIPTOR_PROPS.has (key)) {
        return hash;
      }

      hash[key] = {
        value: getTvalue (valuePath).trim (),
        loc: locPath.node
      };
      return hash;
    }, {});
  }

  function storeMessage (msg, path, state) {
    state.T.messages.push (msg);
  }

  function referencesImport (path, mod, importedNames) {
    if (!(path.isIdentifier () || path.isJSXIdentifier ())) {
      return false;
    }

    return importedNames.some (name => path.referencesImport (mod, name));
  }

  return {
    visitor: {
      Program: {
        enter (path, state) {
          state.T = {
            messages: [],
          };
        },

        exit (path, state) {
          const opts = state.opts;
          const file = state.file;
          file.metadata['react-nabu'] = state.T;

          // FIXME: broken because lowdb is used with async writer
          // state.T.messages.forEach (msg => nabuExtractor (msg.msgid.value, msg.msgid.desc));
        },
      },

      JSXOpeningElement (path, state) {
        const opts = state.opts;
        const moduleSourceName = getModuleSourceName (opts);

        let name = path.get ('name');

        if (referencesImport (name, moduleSourceName, COMPONENT_NAMES)) {
          let attributes = path
            .get ('attributes')
            .filter (attr => attr.isJSXAttribute ());

          let descriptor = createTdescriptor (
            attributes.map (attr => [
              attr.get ('name'),
              attr.get ('value'),
              attr.get ('loc')
            ]), {
              isJSXSource: true
            }
          );

          storeMessage (descriptor, path, state);
        }
      },

      CallExpression (path, state) {},
    },
  };
};
<commit_msg>Remove mosty of linter warnings<commit_after>'use strict';

const nabuExtractor = require ('nabu-extractor');

/*
 * Inspired by the work of Yahoo for babel-plugin-react-intl.
 */

const COMPONENT_NAMES = [
  'T'
];
const DESCRIPTOR_PROPS = new Set (['msgid', 'desc']);

module.exports = function () {
  function getModuleSourceName (opts) {
    return opts.moduleSourceName || 'react-nabu';
  }

  function getTkey (path) {
    if (path.isIdentifier () || path.isJSXIdentifier ()) {
      return path.node.name;
    }

    let evaluated = path.evaluate ();
    if (evaluated.confident) {
      return evaluated.value;
    }

    throw path.buildCodeFrameError ('[T] msgid must be statically evaluate-able for extraction.');
  }

  function getTvalue (path) {
    if (path.isJSXExpressionContainer ()) {
      path = path.get ('expression');
    }

    let evaluated = path.evaluate ();
    if (evaluated.confident) {
      return evaluated.value;
    }

    throw path.buildCodeFrameError ('[T] msgid must be statically evaluate-able for extraction.');
  }

  function createTdescriptor (propPaths, options) {
    if (!options) {
      options = {};
    }
    const isJSXSource = options.isJSXSource || false;

    return propPaths.reduce ((hash, arr) => {
      let keyPath   = arr[0];
      let valuePath = arr[1];
      let locPath   = arr[2];

      let key = getTkey (keyPath);

      if (!DESCRIPTOR_PROPS.has (key)) {
        return hash;
      }

      hash[key] = {
        value: getTvalue (valuePath).trim (),
        loc: locPath.node
      };
      return hash;
    }, {});
  }

  function storeMessage (msg, path, state) {
    state.T.messages.push (msg);
  }

  function referencesImport (path, mod, importedNames) {
    if (!(path.isIdentifier () || path.isJSXIdentifier ())) {
      return false;
    }

    return importedNames.some (name => path.referencesImport (mod, name));
  }

  return {
    visitor: {
      Program: {
        enter (path, state) {
          state.T = {
            messages: [],
          };
        },

        exit (path, state) {
          const {file} = state;
          file.metadata['react-nabu'] = state.T;

          // FIXME: broken because lowdb is used with async writer
          // state.T.messages.forEach (msg => nabuExtractor (msg.msgid.value, msg.msgid.desc));
        },
      },

      JSXOpeningElement (path, state) {
        const opts = state.opts;
        const moduleSourceName = getModuleSourceName (opts);

        const name = path.get ('name');

        if (referencesImport (name, moduleSourceName, COMPONENT_NAMES)) {
          const attributes = path
            .get ('attributes')
            .filter (attr => attr.isJSXAttribute ());

          const descriptor = createTdescriptor (
            attributes.map (attr => [
              attr.get ('name'),
              attr.get ('value'),
              attr.get ('loc')
            ]), {
              isJSXSource: true
            }
          );

          storeMessage (descriptor, path, state);
        }
      },

      CallExpression () {},
    },
  };
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */

var each = require('component-each');
var integration = require('@segment/analytics.js-integration');
var tick = require('next-tick');

/**
 * Expose `VWO` integration.
 */

var VWO = module.exports = integration('Visual Website Optimizer')
  .global('_vis_opt_queue')
  .global('_vis_opt_revenue_conversion')
  .global('_vwo_exp')
  .global('_vwo_exp_ids')
  .option('replay', true)
  .option('listen', false);

/**
 * The context for this integration.
 */

var integrationContext = {
  name: 'visual-website-optimizer',
  version: '1.0.0'
};

/**
 * Initialize.
 *
 * http://v2.visualwebsiteoptimizer.com/tools/get_tracking_code.php
 */

VWO.prototype.initialize = function() {
  var self = this;
  if (this.options.replay) {
    tick(function() {
      self.replay();
    });
  }
  if (this.options.listen) {
    tick(function() {
      self.roots();
    });
  }
  this.ready();
};

/**
 * Completed Purchase.
 *
 * https://vwo.com/knowledge/vwo-revenue-tracking-goal
 */

VWO.prototype.orderCompleted = function(track) {
  var total = track.total() || track.revenue() || 0;
  enqueue(function() {
    window._vis_opt_revenue_conversion(total);
  });
};

/**
 * Replay the experiments the user has seen as traits to all other integrations.
 * Wait for the next tick to replay so that the `analytics` object and all of
 * the integrations are fully initialized.
 */

VWO.prototype.replay = function() {
  var analytics = this.analytics;

  experiments(function(err, traits) {
    if (traits) analytics.identify(traits);
  });
};

/**
 * Replay the experiments the user has seen as traits to all other integrations.
 * Wait for the next tick to replay so that the `analytics` object and all of
 * the integrations are fully initialized.
 */

VWO.prototype.roots = function() {
  var analytics = this.analytics;

  rootExperiments(function(err, data) {
    each(data, function(experimentId, variationName) {
      analytics.track(
        'Experiment Viewed',
        {
          experimentId: experimentId,
          variationName: variationName
        },
        { context: { integration: integrationContext } }
      );
    });
  });
};

/**
 * Get dictionary of experiment keys and variations.
 *
 * http://visualwebsiteoptimizer.com/knowledge/integration-of-vwo-with-kissmetrics/
 *
 * @param {Function} fn
 * @return {Object}
 */

function rootExperiments(fn) {
  enqueue(function() {
    var data = {};
    var experimentIds = window._vwo_exp_ids;
    if (!experimentIds) return fn();
    each(experimentIds, function(experimentId) {
      var variationName = variation(experimentId);
      if (variationName) data[experimentId] = variationName;
    });
    fn(null, data);
  });
}

/**
 * Get dictionary of experiment keys and variations.
 *
 * http://visualwebsiteoptimizer.com/knowledge/integration-of-vwo-with-kissmetrics/
 *
 * @param {Function} fn
 * @return {Object}
 */

function experiments(fn) {
  enqueue(function() {
    var data = {};
    var ids = window._vwo_exp_ids;
    if (!ids) return fn();
    each(ids, function(id) {
      var name = variation(id);
      if (name) data['Experiment: ' + id] = name;
    });
    fn(null, data);
  });
}

/**
 * Add a `fn` to the VWO queue, creating one if it doesn't exist.
 *
 * @param {Function} fn
 */

function enqueue(fn) {
  window._vis_opt_queue = window._vis_opt_queue || [];
  window._vis_opt_queue.push(fn);
}

/**
 * Get the chosen variation's name from an experiment `id`.
 *
 * http://visualwebsiteoptimizer.com/knowledge/integration-of-vwo-with-kissmetrics/
 *
 * @param {String} id
 * @return {String}
 */

function variation(id) {
  var experiments = window._vwo_exp;
  if (!experiments) return null;
  var experiment = experiments[id];
  var variationId = experiment.combination_chosen;

  // Send data only if experiment is marked ready by VWO and User is not previewing the VWO campaign
  if (experiment.ready && !window._vis_debug && variationId) {
    return experiment.comb_n[variationId];
  }
  return null;
}
<commit_msg>Add support for async VWO snippet (#9)<commit_after>/* eslint-disable strict */

/**
 * Module dependencies.
 */

var each = require('component-each');
var integration = require('@segment/analytics.js-integration');
var tick = require('next-tick');

/**
 * Expose `VWO` integration.
 */

var VWO = module.exports = integration('Visual Website Optimizer')
  .global('_vis_opt_queue')
  .global('_vis_opt_revenue_conversion')
  .global('_vwo_exp')
  .global('_vwo_exp_ids')
  .option('accountId')
  .option('useAsyncSmartCode', false)
  .option('settingsTolerance', 2000)
  .option('libraryTolerance', 2500)
  .option('useExistingJQuery', false)
  .option('replay', true)
  .option('listen', false);

/**
 * The context for this integration.
 */

var integrationContext = {
  name: 'visual-website-optimizer',
  version: '1.0.0'
};

/**
 * Initialize.
 */

VWO.prototype.initialize = function() {
  if (this.options.useAsyncSmartCode) {
    /* eslint-disable */
    var account_id = this.options.accountId;
    var settings_tolerance = this.options.settingsTolerance;
    var library_tolerance = this.options.libraryTolerance;
    var use_existing_jquery = this.options.useExistingJQuery;

    window._vwo_code=(function(){f=false,d=document;return{use_existing_jquery:function(){return use_existing_jquery;},library_tolerance:function(){return library_tolerance;},finish:function(){if(!f){f=true;var a=d.getElementById('_vis_opt_path_hides');if(a)a.parentNode.removeChild(a);}},finished:function(){return f;},load:function(a){var b=d.createElement('script');b.src=a;b.type='text/javascript';b.innerText;b.onerror=function(){_vwo_code.finish();};d.getElementsByTagName('head')[0].appendChild(b);},init:function(){settings_timer=setTimeout('_vwo_code.finish()',settings_tolerance);var a=d.createElement('style'),b='body{opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important;}',h=d.getElementsByTagName('head')[0];a.setAttribute('id','_vis_opt_path_hides');a.setAttribute('type','text/css');if(a.styleSheet)a.styleSheet.cssText=b;else a.appendChild(d.createTextNode(b));h.appendChild(a);this.load('//dev.visualwebsiteoptimizer.com/j.php?a='+account_id+'&u='+encodeURIComponent(d.URL)+'&r='+Math.random());return settings_timer;}};}());_vwo_settings_timer=_vwo_code.init();
    /* eslint-enable */
  }

  var self = this;

  if (this.options.replay) {
    tick(function() {
      self.replay();
    });
  }

  if (this.options.listen) {
    tick(function() {
      self.roots();
    });
  }

  if (this.options.useAsyncSmartCode) {
    enqueue(function() {
      self.ready();
    });
  } else {
    self.ready();
  }
};

/**
 * Completed Purchase.
 *
 * https://vwo.com/knowledge/vwo-revenue-tracking-goal
 */

VWO.prototype.orderCompleted = function(track) {
  var total = track.total() || track.revenue() || 0;
  enqueue(function() {
    window._vis_opt_revenue_conversion(total);
  });
};

/**
 * Replay the experiments the user has seen as traits to all other integrations.
 * Wait for the next tick to replay so that the `analytics` object and all of
 * the integrations are fully initialized.
 */

VWO.prototype.replay = function() {
  var analytics = this.analytics;

  experiments(function(err, traits) {
    if (traits) analytics.identify(traits);
  });
};

/**
 * Replay the experiments the user has seen as traits to all other integrations.
 * Wait for the next tick to replay so that the `analytics` object and all of
 * the integrations are fully initialized.
 */

VWO.prototype.roots = function() {
  var analytics = this.analytics;

  rootExperiments(function(err, data) {
    each(data, function(experimentId, variationName) {
      analytics.track(
        'Experiment Viewed',
        {
          experimentId: experimentId,
          variationName: variationName
        },
        { context: { integration: integrationContext } }
      );
    });
  });
};

/**
 * Get dictionary of experiment keys and variations.
 *
 * http://visualwebsiteoptimizer.com/knowledge/integration-of-vwo-with-kissmetrics/
 *
 * @param {Function} fn
 * @return {Object}
 */

function rootExperiments(fn) {
  enqueue(function() {
    var data = {};
    var experimentIds = window._vwo_exp_ids;
    if (!experimentIds) return fn();
    each(experimentIds, function(experimentId) {
      var variationName = variation(experimentId);
      if (variationName) data[experimentId] = variationName;
    });
    fn(null, data);
  });
}

/**
 * Get dictionary of experiment keys and variations.
 *
 * http://visualwebsiteoptimizer.com/knowledge/integration-of-vwo-with-kissmetrics/
 *
 * @param {Function} fn
 * @return {Object}
 */

function experiments(fn) {
  enqueue(function() {
    var data = {};
    var ids = window._vwo_exp_ids;
    if (!ids) return fn();
    each(ids, function(id) {
      var name = variation(id);
      if (name) data['Experiment: ' + id] = name;
    });
    fn(null, data);
  });
}

/**
 * Add a `fn` to the VWO queue, creating one if it doesn't exist.
 *
 * @param {Function} fn
 */

function enqueue(fn) {
  window._vis_opt_queue = window._vis_opt_queue || [];
  window._vis_opt_queue.push(fn);
}

/**
 * Get the chosen variation's name from an experiment `id`.
 *
 * http://visualwebsiteoptimizer.com/knowledge/integration-of-vwo-with-kissmetrics/
 *
 * @param {String} id
 * @return {String}
 */

function variation(id) {
  var experiments = window._vwo_exp;
  if (!experiments) return null;
  var experiment = experiments[id];
  var variationId = experiment.combination_chosen;

  // Send data only if experiment is marked ready by VWO and User is not previewing the VWO campaign
  if (experiment.ready && !window._vis_debug && variationId) {
    return experiment.comb_n[variationId];
  }
  return null;
}
<|endoftext|>


<commit_before>/* jshint esversion:6, node: true */

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();

app.set('port', (process.env.PORT || 5000));

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}));

// parse application/json
app.use(bodyParser.json());

// index
app.get('/', function (req, res) {
	res.send('hello world i am a secret bot');
});

// for facebook verification
app.get('/webhook/', function (req, res) {
	if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
		res.send(req.query['hub.challenge']);
	} else {
		res.send('Error, wrong token');
	}
});

// to post data
app.post('/webhook/', function (req, res) {
	let messaging_events = req.body.entry[0].messaging;
	for (let i = 0; i < messaging_events.length; i++) {
		let event = req.body.entry[0].messaging[i];
		let sender = event.sender.id;

		if (event.message && event.message.text) {
			let text = event.message.text;
			if (text === 'Generic') {
				sendGenericMessage(sender);
				continue;
			}

			else if (text == 'cookies'){
				var headers = {
				    'Authorization': 'bearer fd887ce5-7b15-4c1e-93a0-dc91ce883ec6'
				};

				var options = {
				    url: 'https://www.loblaws.ca/ecommerce/v2/loblaw/products/search?q=apple&page=0&pageSize=10&sort=recommended&filters=category:LSL001006000000',
				    headers: headers
				};

				function callback(error, response, body) {
				    if (!error && response.statusCode == 200) {
				        console.log(body);
				        sendTextMessage(sender, body, token);
				        var resp = JSON.parse(body);
				        var results = resp["searchResults"["products"]];
				        console.log(results[0].productName);
				    }
				}

				request(options, callback);

			}
			sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200));
		}
		if (event.postback) {
			let text = JSON.stringify(event.postback);
			sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token);
			continue;
		}
	}
	res.sendStatus(200);
});

// recommended to inject access tokens as environmental variables, e.g.
const token = process.env.PAGE_ACCESS_TOKEN;
//const token = "<PAGE_ACCESS_TOKEN>"

function sendTextMessage(sender, text) {
	let messageData = { text:text };

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

function sendGenericMessage(sender) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "generic",
				"elements": [{
					"title": "First card",
					"subtitle": "Element #1 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
					"buttons": [{
						"type": "web_url",
						"url": "https://www.messenger.com",
						"title": "web url"
					}, {
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for first element in a generic bubble",
					}],
				}, {
					"title": "Second card",
					"subtitle": "Element #2 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
					"buttons": [{
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for second element in a generic bubble",
					}],
				}]
			}
		}
	};
	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

// spin spin sugar
app.listen(app.get('port'), function() {
	console.log('running on port', app.get('port'));
});
<commit_msg>heroku<commit_after>/* jshint esversion:6, node: true */

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();

app.set('port', (process.env.PORT || 5000));

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}));

// parse application/json
app.use(bodyParser.json());

// index
app.get('/', function (req, res) {
	res.send('hello world i am a secret bot');
});

// for facebook verification
app.get('/webhook/', function (req, res) {
	if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
		res.send(req.query['hub.challenge']);
	} else {
		res.send('Error, wrong token');
	}
});

// to post data
app.post('/webhook/', function (req, res) {
	let messaging_events = req.body.entry[0].messaging;
	for (let i = 0; i < messaging_events.length; i++) {
		let event = req.body.entry[0].messaging[i];
		let sender = event.sender.id;

		if (event.message && event.message.text) {
			let text = event.message.text;
			if (text === 'Generic') {
				sendGenericMessage(sender);
				continue;
			}

			else if (text == 'cookies'){
				var headers = {
				    'Authorization': 'bearer fd887ce5-7b15-4c1e-93a0-dc91ce883ec6'
				};

				var options = {
				    url: 'https://www.loblaws.ca/ecommerce/v2/loblaw/products/search?q=apple&page=0&pageSize=10&sort=recommended&filters=category:LSL001006000000',
				    headers: headers
				};

				function callback(error, response, body) {
				    if (!error && response.statusCode == 200) {
				        console.log(body);
				        sendTextMessage(sender, body, token);
				        var resp = JSON.parse(body);
				        var results = resp["searchResults"];
				        console.log(results[0]);
				    }
				}

				request(options, callback);

			}
			sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200));
		}
		if (event.postback) {
			let text = JSON.stringify(event.postback);
			sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token);
			continue;
		}
	}
	res.sendStatus(200);
});

// recommended to inject access tokens as environmental variables, e.g.
const token = process.env.PAGE_ACCESS_TOKEN;
//const token = "<PAGE_ACCESS_TOKEN>"

function sendTextMessage(sender, text) {
	let messageData = { text:text };

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

function sendGenericMessage(sender) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "generic",
				"elements": [{
					"title": "First card",
					"subtitle": "Element #1 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
					"buttons": [{
						"type": "web_url",
						"url": "https://www.messenger.com",
						"title": "web url"
					}, {
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for first element in a generic bubble",
					}],
				}, {
					"title": "Second card",
					"subtitle": "Element #2 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
					"buttons": [{
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for second element in a generic bubble",
					}],
				}]
			}
		}
	};
	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

// spin spin sugar
app.listen(app.get('port'), function() {
	console.log('running on port', app.get('port'));
});
<|endoftext|>


<commit_before>var index = {
    Client: "client",
    Message : 'message',
    OutputSocket : 'output-socket',
    MessageParser : 'message-parser',
    // ChunkedMessageParser: 'chunked-message-parser',
    CommandParser : 'command-parser',
    Bisubscriber : 'bisubscriber'
};

for (var m in index) {
    index[m] = require('./' + index[m]);
}

module.exports = index;
<commit_msg>index.js<commit_after>var index = {
    Client: "client",
    Message : 'message',
    //OutputSocket : 'output-socket',
    //MessageHandler : 'message-handler',
    CommandHandler : 'command-handler',
    //Bisubscriber : 'bisubscriber'
};

for (var m in index) {
    index[m] = require('./' + index[m]);
}

module.exports = index;
<|endoftext|>


<commit_before>import { NativeEventEmitter, NativeModules, View } from 'react-native';
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';

const { TrackPlayer } = NativeModules;
const eventEmitter = new NativeEventEmitter(TrackPlayer);

function resolveAsset(uri) {
    if(!uri) return undefined;
    return resolveAssetSource(uri);
}

function resolveUrl(url) {
    if(!url) return undefined;
    return resolveAssetSource(url) || url;
}

function updateOptions(data) {
    // Resolve the asset for each icon
    data.icon = resolveAsset(data.icon);
    data.playIcon = resolveAsset(data.playIcon);
    data.pauseIcon = resolveAsset(data.pauseIcon);
    data.stopIcon = resolveAsset(data.stopIcon);
    data.previousIcon = resolveAsset(data.previousIcon);
    data.nextIcon = resolveAsset(data.nextIcon);

    return TrackPlayer.updateOptions(data);
}

function add(tracks, insertBeforeId) {
    if(!Array.isArray(tracks)) {
        tracks = [tracks];
    }

    // Resolve the URL for each track
    for(let i = 0; i < tracks.length; i++) {
        tracks[i].url = resolveUrl(tracks[i].url);
        tracks[i].artwork = resolveUrl(tracks[i].artwork);
    }

    return TrackPlayer.add(tracks, insertBeforeId);
}

function remove(tracks) {
    if(!Array.isArray(tracks)) {
        tracks = [tracks];
    }

    return TrackPlayer.remove(tracks);
}

// We'll declare each one of the constants and functions manually so IDEs can show a list of them
// We should also add documentation here, but I'll leave this task to another day

// States
module.exports.STATE_NONE = TrackPlayer.STATE_NONE;
module.exports.STATE_PLAYING = TrackPlayer.STATE_PLAYING;
module.exports.STATE_PAUSED = TrackPlayer.STATE_PAUSED;
module.exports.STATE_STOPPED = TrackPlayer.STATE_STOPPED;
module.exports.STATE_BUFFERING = TrackPlayer.STATE_BUFFERING;

// Capabilities
module.exports.CAPABILITY_PLAY = TrackPlayer.CAPABILITY_PLAY;
module.exports.CAPABILITY_PLAY_FROM_ID = TrackPlayer.CAPABILITY_PLAY_FROM_ID;
module.exports.CAPABILITY_PLAY_FROM_SEARCH = TrackPlayer.CAPABILITY_PLAY_FROM_SEARCH;
module.exports.CAPABILITY_PAUSE = TrackPlayer.CAPABILITY_PAUSE;
module.exports.CAPABILITY_STOP = TrackPlayer.CAPABILITY_STOP;
module.exports.CAPABILITY_SEEK_TO = TrackPlayer.CAPABILITY_SEEK_TO;
module.exports.CAPABILITY_SKIP = TrackPlayer.CAPABILITY_SKIP;
module.exports.CAPABILITY_SKIP_TO_NEXT = TrackPlayer.CAPABILITY_SKIP_TO_NEXT;
module.exports.CAPABILITY_SKIP_TO_PREVIOUS = TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS;
module.exports.CAPABILITY_SET_RATING = TrackPlayer.CAPABILITY_SET_RATING;

// Rating Types
module.exports.RATING_HEART = TrackPlayer.RATING_HEART;
module.exports.RATING_THUMBS_UP_DOWN = TrackPlayer.RATING_THUMBS_UP_DOWN;
module.exports.RATING_3_STARS = TrackPlayer.RATING_3_STARS;
module.exports.RATING_4_STARS = TrackPlayer.RATING_4_STARS;
module.exports.RATING_5_STARS = TrackPlayer.RATING_5_STARS;
module.exports.RATING_PERCENTAGE = TrackPlayer.RATING_PERCENTAGE;

// Cast States
module.exports.CAST_NO_DEVICES_AVAILABLE = TrackPlayer.CAST_NO_DEVICES_AVAILABLE;
module.exports.CAST_NOT_CONNECTED = TrackPlayer.CAST_NOT_CONNECTED;
module.exports.CAST_CONNECTING = TrackPlayer.CAST_CONNECTING;
module.exports.CAST_CONNECTED = TrackPlayer.CAST_CONNECTED;

// Player Lifecycle
module.exports.setupPlayer = TrackPlayer.setupPlayer;
module.exports.destroy = TrackPlayer.destroy;

// Player Options
module.exports.updateOptions = updateOptions;

// Player Queue Commands
module.exports.add = add;
module.exports.remove = remove;
module.exports.skip = TrackPlayer.skip;
module.exports.skipToNext = TrackPlayer.skipToNext;
module.exports.skipToPrevious = TrackPlayer.skipToPrevious;

// Player Playback Commands
module.exports.reset = TrackPlayer.reset;
module.exports.play = TrackPlayer.play;
module.exports.pause = TrackPlayer.pause;
module.exports.stop = TrackPlayer.stop;
module.exports.seekTo = TrackPlayer.seekTo;
module.exports.setVolume = TrackPlayer.setVolume;

// Player Getters
module.exports.getTrack = TrackPlayer.getTrack;
module.exports.getCurrentTrack = TrackPlayer.getCurrentTrack;
module.exports.getVolume = TrackPlayer.getVolume;
module.exports.getDuration = TrackPlayer.getDuration;
module.exports.getPosition = TrackPlayer.getPosition;
module.exports.getBufferedPosition = TrackPlayer.getBufferedPosition;
module.exports.getState = TrackPlayer.getState;

// Cast Getters
module.exports.getCastState = TrackPlayer.getCastState;

// Components
if(TrackPlayer.CAST_SUPPORT_AVAILABLE) {
    module.exports.CastButton = require('./CastButton');
} else {
    module.exports.CastButton = View; // Cast Unavailable
}
<commit_msg>Export ios event emitter<commit_after>import { NativeEventEmitter, NativeModules, View } from 'react-native';
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';

const { TrackPlayer } = NativeModules;
const eventEmitter = new NativeEventEmitter(TrackPlayer);

function resolveAsset(uri) {
    if(!uri) return undefined;
    return resolveAssetSource(uri);
}

function resolveUrl(url) {
    if(!url) return undefined;
    return resolveAssetSource(url) || url;
}

function updateOptions(data) {
    // Resolve the asset for each icon
    data.icon = resolveAsset(data.icon);
    data.playIcon = resolveAsset(data.playIcon);
    data.pauseIcon = resolveAsset(data.pauseIcon);
    data.stopIcon = resolveAsset(data.stopIcon);
    data.previousIcon = resolveAsset(data.previousIcon);
    data.nextIcon = resolveAsset(data.nextIcon);

    return TrackPlayer.updateOptions(data);
}

function add(tracks, insertBeforeId) {
    if(!Array.isArray(tracks)) {
        tracks = [tracks];
    }

    // Resolve the URL for each track
    for(let i = 0; i < tracks.length; i++) {
        tracks[i].url = resolveUrl(tracks[i].url);
        tracks[i].artwork = resolveUrl(tracks[i].artwork);
    }

    return TrackPlayer.add(tracks, insertBeforeId);
}

function remove(tracks) {
    if(!Array.isArray(tracks)) {
        tracks = [tracks];
    }

    return TrackPlayer.remove(tracks);
}

// We'll declare each one of the constants and functions manually so IDEs can show a list of them
// We should also add documentation here, but I'll leave this task to another day

// States
module.exports.STATE_NONE = TrackPlayer.STATE_NONE;
module.exports.STATE_PLAYING = TrackPlayer.STATE_PLAYING;
module.exports.STATE_PAUSED = TrackPlayer.STATE_PAUSED;
module.exports.STATE_STOPPED = TrackPlayer.STATE_STOPPED;
module.exports.STATE_BUFFERING = TrackPlayer.STATE_BUFFERING;

// Capabilities
module.exports.CAPABILITY_PLAY = TrackPlayer.CAPABILITY_PLAY;
module.exports.CAPABILITY_PLAY_FROM_ID = TrackPlayer.CAPABILITY_PLAY_FROM_ID;
module.exports.CAPABILITY_PLAY_FROM_SEARCH = TrackPlayer.CAPABILITY_PLAY_FROM_SEARCH;
module.exports.CAPABILITY_PAUSE = TrackPlayer.CAPABILITY_PAUSE;
module.exports.CAPABILITY_STOP = TrackPlayer.CAPABILITY_STOP;
module.exports.CAPABILITY_SEEK_TO = TrackPlayer.CAPABILITY_SEEK_TO;
module.exports.CAPABILITY_SKIP = TrackPlayer.CAPABILITY_SKIP;
module.exports.CAPABILITY_SKIP_TO_NEXT = TrackPlayer.CAPABILITY_SKIP_TO_NEXT;
module.exports.CAPABILITY_SKIP_TO_PREVIOUS = TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS;
module.exports.CAPABILITY_SET_RATING = TrackPlayer.CAPABILITY_SET_RATING;

// Rating Types
module.exports.RATING_HEART = TrackPlayer.RATING_HEART;
module.exports.RATING_THUMBS_UP_DOWN = TrackPlayer.RATING_THUMBS_UP_DOWN;
module.exports.RATING_3_STARS = TrackPlayer.RATING_3_STARS;
module.exports.RATING_4_STARS = TrackPlayer.RATING_4_STARS;
module.exports.RATING_5_STARS = TrackPlayer.RATING_5_STARS;
module.exports.RATING_PERCENTAGE = TrackPlayer.RATING_PERCENTAGE;

// Cast States
module.exports.CAST_NO_DEVICES_AVAILABLE = TrackPlayer.CAST_NO_DEVICES_AVAILABLE;
module.exports.CAST_NOT_CONNECTED = TrackPlayer.CAST_NOT_CONNECTED;
module.exports.CAST_CONNECTING = TrackPlayer.CAST_CONNECTING;
module.exports.CAST_CONNECTED = TrackPlayer.CAST_CONNECTED;

// Player Lifecycle
module.exports.setupPlayer = TrackPlayer.setupPlayer;
module.exports.destroy = TrackPlayer.destroy;

// Player Options
module.exports.updateOptions = updateOptions;

// Player Queue Commands
module.exports.add = add;
module.exports.remove = remove;
module.exports.skip = TrackPlayer.skip;
module.exports.skipToNext = TrackPlayer.skipToNext;
module.exports.skipToPrevious = TrackPlayer.skipToPrevious;

// Player Playback Commands
module.exports.reset = TrackPlayer.reset;
module.exports.play = TrackPlayer.play;
module.exports.pause = TrackPlayer.pause;
module.exports.stop = TrackPlayer.stop;
module.exports.seekTo = TrackPlayer.seekTo;
module.exports.setVolume = TrackPlayer.setVolume;

// Player Getters
module.exports.getTrack = TrackPlayer.getTrack;
module.exports.getCurrentTrack = TrackPlayer.getCurrentTrack;
module.exports.getVolume = TrackPlayer.getVolume;
module.exports.getDuration = TrackPlayer.getDuration;
module.exports.getPosition = TrackPlayer.getPosition;
module.exports.getBufferedPosition = TrackPlayer.getBufferedPosition;
module.exports.getState = TrackPlayer.getState;

// Event Emitter
module.exports.eventEmitter = eventEmitter;

// Cast Getters
module.exports.getCastState = TrackPlayer.getCastState;

// Components
if(TrackPlayer.CAST_SUPPORT_AVAILABLE) {
    module.exports.CastButton = require('./CastButton');
} else {
    module.exports.CastButton = View; // Cast Unavailable
}
<|endoftext|>


<commit_before>"use strict";

const expect = require("expect")
    , colorIt = require("color-it")
    , emoji = require("emojic")
    , Queue = require("queoid")
    , indento = require("indento")
    , tryAsync = require("try-async");
    ;

class Describe {

    /**
     * Describe
     * Creates a new `Describe` instance.
     *
     * To change the default configuration, you can override the `tester` fields:
     *
     * ```js
     * var tester = require("tester");
     * ```
     *
     * #### Colors
     *
     * `tester` uses [`color-it`](https://github.com/IonicaBizau/node-color-it)
     * to color the messages. You can use any available color name (defaults are listed):
     *
     *  - `colors` (Object):
     *    - `it` (Object)
     *      - `success`: `"green"`
     *      - `error`: `"red"`
     *    - `describe`: `"yellow"`
     *
     * For example, to have [**blue**](#) describe messages, you will do: `tester.colors.describe = "blue"`.
     *
     * #### Icons
     *
     * `tester` uses emoji provided by [`emojic`](https://github.com/IonicaBizau/emojic):
     *
     *   - `icons`
     *     - `it`
     *       - `success`: `"zap"`
     *       - `error`: `"x"`
     *     - `describe`: `"arrowRight"`
     *
     * #### Indent
     *
     * `tester` uses [`indento`](https://github.com/IonicaBizau/indento) to indent the strings:
     *
     *  - `indent`
     *    - `it`: `5`
     *    - `describe`: `2`
     *
     * #### Loggers
     *
     * You can override any of the following functions:
     *
     *  - `loggers`
     *    - `it (err, itMessage, icon)`
     *    - `describe (message)`
     *
     * @name Describe
     * @function
     * @param {String} message The `Describe` message.
     * @param {Function} fn The callback function.
     */
    constructor (message, fn) {
        this.queue = new Queue();
        this.message = message;
        this.fn = fn;
    }

    /**
     * run
     * Runs the tests from this group.
     *
     * @name run
     * @function
     * @param {Function} fn The callback function.
     */
    run (fn) {
        tester.loggers.describe(this.message);
        this.fn(this);
        this.queue.start(fn);
    }

    /**
     * expect
     * This is a wrapper around the `expect` package.
     *
     * @name expect
     * @function
     * @return {Expect} The `Expect` result.
     */
    expect () {
        return expect.apply(this, arguments);
    }

    /**
     * it
     * Adds a new test in the describe queue.
     *
     * @name it
     * @function
     * @param {String} what The test message.
     * @param {Function} fn The callback function.
     */
    it (what, fn) {

        var _fn = cb => {

            var _this = {
                    ended: false
                  , end: (e, m) => {
                        if (_this.ended) {
                            return;
                        }
                        m = m || what;
                        _this.ended = true;
                        tester.loggers.it(e, m);
                        cb();
                    }
                  , error: (e) => {
                        _this.end(e, what);
                    }
                  , pass: () => {
                        _this.end(null, what);
                    }
                  , expect: expect
                }
              , _err = null
              , _args = []
              ;

            if (fn.length) {
                _args.push(_this.end);
            }

            tryAsync(function () {
                fn.apply(_this, _args);
            }, e => _this.error(e));

            if (!_args.length) {
                _this.end();
            }
        };

        this.queue.push(_fn);
    }

    /**
     * should
     * Adds a new test in the describe queue prefixing the message with *should*.
     *
     * @name should
     * @function
     * @param {String} what The test message.
     * @param {Function} fn The callback function.
     */
    should (what, fn) {
        this.it(`should ${what}`, fn);
    }
}

var tester = module.exports = {
    queue: new Queue()
  , colors: {
        it: {
            success: "green"
          , error: "red"
        }
      , describe: "yellow"
    }
  , icons: {
        it: {
            success: "zap"
          , error: "x"
        }
      , describe: "arrowRight"
    }
  , indent: {
        it: 5
      , describe: 2
    }
  , loggers: {
        it: (err, itMessage, icon) => {
            icon = icon || tester.icons.it[err ?  "error" : "success"];
            var message = emoji[icon] + " " + itMessage;

            if (err) {
                message += "\n" + err;
            }

            console.log(
                indento(
                    colorIt(message)[tester.colors.it[err ? "error" : "success"]]().toString()
                  , tester.indent.it
                )
            );
        }
      , describe: (message) => {
            console.log(
                indento(
                    colorIt(
                        emoji[tester.icons.describe]
                      + " " + message
                    )[tester.colors.describe]().toString()
                  , tester.indent.describe
                )
            );
        }
    }
};

function generateQueueHandler(desc) {
    return function (cb) {
        desc.run(cb);
    }
}

/**
 * describe
 * Groups more tests together.
 *
 * @name describe
 * @function
 * @param {String} what The describe message.
 * @param {Function} fn The callback function.
 */
tester.describe = function (what, fn) {
    tester.queue.push(generateQueueHandler(new Describe(what, fn)));
    tester.queue.start();
};
<commit_msg>Use emoji-logger for logging the things<commit_after>"use strict";

const expect = require("expect")
    , Queue = require("queoid")
    , tryAsync = require("try-async")
    , logger = require("emoji-logger")
    ;

class Describe {

    /**
     * Describe
     * Creates a new `Describe` instance.
     *
     * To change the default configuration, you can override the `tester` fields:
     *
     * ```js
     * var tester = require("tester");
     * ```
     *
     * #### Colors
     *
     * `tester` uses [`color-it`](https://github.com/IonicaBizau/node-color-it)
     * to color the messages. You can use any available color name (defaults are listed):
     *
     *  - `colors` (Object):
     *    - `it` (Object)
     *      - `success`: `"green"`
     *      - `error`: `"red"`
     *    - `describe`: `"yellow"`
     *
     * For example, to have [**blue**](#) describe messages, you will do: `tester.colors.describe = "blue"`.
     *
     * #### Icons
     *
     * `tester` uses emoji provided by [`emojic`](https://github.com/IonicaBizau/emojic):
     *
     *   - `icons`
     *     - `it`
     *       - `success`: `"zap"`
     *       - `error`: `"x"`
     *     - `describe`: `"arrowRight"`
     *
     * #### Indent
     *
     * `tester` uses [`indento`](https://github.com/IonicaBizau/indento) to indent the strings:
     *
     *  - `indent`
     *    - `it`: `5`
     *    - `describe`: `2`
     *
     * #### Loggers
     *
     * You can override any of the following fields
     *
     *  - `loggers`
     *    - `stream`: The stream where the messages will be written (default: `process.stdout`).
     *    - `it (err, itMessage, icon)`
     *    - `describe (message)`
     *
     * @name Describe
     * @function
     * @param {String} message The `Describe` message.
     * @param {Function} fn The callback function.
     */
    constructor (message, fn) {
        this.queue = new Queue();
        this.message = message;
        this.fn = fn;
    }

    /**
     * run
     * Runs the tests from this group.
     *
     * @name run
     * @function
     * @param {Function} fn The callback function.
     */
    run (fn) {
        tester.loggers.describe(this.message);
        this.fn(this);
        this.queue.start(fn);
    }

    /**
     * expect
     * This is a wrapper around the `expect` package.
     *
     * @name expect
     * @function
     * @return {Expect} The `Expect` result.
     */
    expect () {
        return expect.apply(this, arguments);
    }

    /**
     * it
     * Adds a new test in the describe queue.
     *
     * @name it
     * @function
     * @param {String} what The test message.
     * @param {Function} fn The callback function.
     */
    it (what, fn) {

        var _fn = cb => {

            var _this = {
                    ended: false
                  , end: (e, m) => {
                        if (_this.ended) {
                            return;
                        }
                        m = m || what;
                        _this.ended = true;
                        tester.loggers.it(e, m);
                        cb();
                    }
                  , error: (e) => {
                        _this.end(e, what);
                    }
                  , pass: () => {
                        _this.end(null, what);
                    }
                  , expect: expect
                }
              , _err = null
              , _args = []
              ;

            if (fn.length) {
                _args.push(_this.end);
            }

            tryAsync(function () {
                fn.apply(_this, _args);
            }, e => _this.error(e));

            if (!_args.length) {
                _this.end();
            }
        };

        this.queue.push(_fn);
    }

    /**
     * should
     * Adds a new test in the describe queue prefixing the message with *should*.
     *
     * @name should
     * @function
     * @param {String} what The test message.
     * @param {Function} fn The callback function.
     */
    should (what, fn) {
        this.it(`should ${what}`, fn);
    }
}

var tester = module.exports = {
    queue: new Queue()
  , colors: {
        it: {
            success: "green"
          , error: "red"
        }
      , describe: "yellow"
    }
  , icons: {
        it: {
            success: "zap"
          , error: "x"
        }
      , describe: "arrowRight"
    }
  , indent: {
        it: 5
      , describe: 2
    }
  , loggers: {
        stream: process.stdout
      , it: (err, itMessage, icon) => {
            icon = icon || tester.icons.it[err ?  "error" : "success"];

            // Build the message
            var message = itMessage;
            if (err) {
                message += "\n" + err;
            }

            logger.log(message, {
                icon: icon
              , type: "tester:it"
              , indent: tester.indent.it
              , color: tester.colors.it[err ? "error" : "success"]
              , stream: tester.loggers.stream
            });
        }
      , describe: (message) => {
            logger.log(message, {
                icon: tester.icons.describe
              , type: "tester:describe"
              , indent: tester.indent.describe
              , color: tester.colors.describe
              , stream: tester.loggers.stream
            });
        }
    }
};

function generateQueueHandler(desc) {
    return function (cb) {
        desc.run(cb);
    }
}

/**
 * describe
 * Groups more tests together.
 *
 * @name describe
 * @function
 * @param {String} what The describe message.
 * @param {Function} fn The callback function.
 */
tester.describe = function (what, fn) {
    tester.queue.push(generateQueueHandler(new Describe(what, fn)));
    tester.queue.start();
};
<|endoftext|>


<commit_before>var EventEmitter = require("events").EventEmitter
  , ShuffleArray = require("shuffle-array")
  , ElmSelect = require("elm-select")
  , Barbe = require("barbe")
  , IterateObject = require("iterate-object")
  , Ul = require("ul")
  ;

function Match(elm, options, data) {
    this.ev = new EventEmitter();
    this.data = options.data || data;

    // [elm, elm]
    this.active = [];

    this.options = Ul.deepMerge(options, {
        size: {
            x: 4
          , y: 4
        }
      , classes: {
            active: "active"
        }
      , step: {
            x: 43
          , y: 43
        }
    });

    this.blocks_count = this.options.size.x * this.options.size.y;

    if (this.blocks_count % 2) {
        throw new Error("The number of blocks should be even.");
    }

    this.ui = {
        container: ElmSelect(elm)[0]
      , items: []
      , template: options.templateElm
                ? ElmSelect(options.templateElm)[0].outerHTML
                : options.template
    };

    if (!Array.isArray(this.data)) {
        throw new Error("Data should be an array.");
    }
}

Match.prototype.on = function () {
    this.ev.on.apply(this.ev, arguments);
};

Match.prototype.emit = function () {
    this.ev.emit.apply(this.ev, arguments);
};

Match.prototype.shuffle = function (arr) {
    return ShuffleArray(arr || this.data);
};

Match.prototype.clear = function () {
    this.ui.container.innerHTML = "";
};

Match.prototype.deactivate = function (elm) {
    elm.classList.remove(this.options.classes.active);
    this.active[this.active.indexOf(elm)] = null;
    this.emit("deactivate", elm);
};

Match.prototype.activate = function (elm) {
    elm.classList.add(this.options.classes.active);
    if (!this.active[0]) {
        this.active[0] = elm;
    } else if (this.active[0] && this.active[1]) {
        this.deactivate(this.active[0]);
        this.deactivate(this.active[1]);
        this.activate(elm);
    } else {
        this.active[1] = elm;
    }
    this.emit("activate", elm);
};

Match.prototype.clicked = function (elm) {
    var self = this;
    elm.addEventListener("click", function () {
        self.activate(this);
    });
};

Match.prototype.addHandlers = function () {
    ElmSelect.call(this, this.ui.container.children, this.clicked);
};

Match.prototype.render = function (clear) {
    var self = this
      , cPos = {
            x: 0
          , y: 0
          , cX: 0
          , cY: 0
        }
      ;

    if (clear) {
       self.clear();
    }

    self.shuffle();
    self.items = self.data.slice(0, this.blocks_count / 2);

    IterateObject(self.items, function (cData, id) {
        for (var newElm, frontElm, backElm, i = 0; i < 2; ++i) {
            newElm = document.createElement("div");
            newElm.setAttribute("data-pattern", id);

            frontElm = document.createElement("div");
            frontElm.classList.add("front");

            backElm = document.createElement("div");
            backElm.classList.add("back");

            newElm.appendChild(frontElm);
            newElm.appendChild(backElm);

            frontElm.innerHTML = Barbe(self.ui.template, cData);

            self.ui.items.push({ element: newElm, data: cData, duplicate: !!i });
            self.emit("render", newElm, cData, i);
        }
    });

    self.shuffle(self.ui.items);

    self.ui.container.innerHTML = self.ui.items.map(function (c) {

        if (cPos.cY === self.options.size.y) {
            return "";
        }

        if (cPos.cX === self.options.size.x) {
            cPos.y += self.options.step.y;
            cPos.x = 0;
            cPos.cX = 0;
            ++cPos.cY;
            if (cPos.cY === self.options.size.y) {
                return "";
            }
        }

        c.element.style.top = cPos.y + "px";
        c.element.style.left = cPos.x + "px";

        cPos.x += self.options.step.x;
        ++cPos.cX;
        return c.element.outerHTML;
    }).join("");

    self.addHandlers();
};

Match.prototype.start = function () {
    var self = this;
    self.render(true);
};

module.exports = Match;
<commit_msg>Check logic<commit_after>var EventEmitter = require("events").EventEmitter
  , ShuffleArray = require("shuffle-array")
  , ElmSelect = require("elm-select")
  , Barbe = require("barbe")
  , IterateObject = require("iterate-object")
  , Ul = require("ul")
  ;

function Match(elm, options, data) {
    this.ev = new EventEmitter();
    this.data = options.data || data;

    // [elm, elm]
    this.active = [];

    this.options = Ul.deepMerge(options, {
        autoremove: true
      , size: {
            x: 4
          , y: 4
        }
      , classes: {
            active: "active"
        }
      , step: {
            x: 43
          , y: 43
        }
    });

    this.blocks_count = this.options.size.x * this.options.size.y;

    if (this.blocks_count % 2) {
        throw new Error("The number of blocks should be even.");
    }

    this.ui = {
        container: ElmSelect(elm)[0]
      , items: []
      , template: options.templateElm
                ? ElmSelect(options.templateElm)[0].outerHTML
                : options.template
    };

    if (!Array.isArray(this.data)) {
        throw new Error("Data should be an array.");
    }
}

Match.prototype.check = function (elm1, elm2) {
    return elm1.getAttribute("data-pattern") === elm2.getAttribute("data-pattern");
};

Match.prototype.on = function () {
    this.ev.on.apply(this.ev, arguments);
};

Match.prototype.emit = function () {
    this.ev.emit.apply(this.ev, arguments);
};

Match.prototype.shuffle = function (arr) {
    return ShuffleArray(arr || this.data);
};

Match.prototype.clear = function () {
    this.ui.container.innerHTML = "";
};

Match.prototype.deactivate = function (elm) {
    elm.classList.remove(this.options.classes.active);
    this.active[this.active.indexOf(elm)] = null;
    this.emit("deactivate", elm);
};

Match.prototype.activate = function (elm) {
    elm.classList.add(this.options.classes.active);
    if (!this.active[0]) {
        this.active[0] = elm;
    } else if (this.active[0] && this.active[1]) {
        if (this.check.call(this, this.active)) {
            this.emit("activate", elm);
            this.emit("success", this.active[0], this.active[1]);
            if (this.options.autoremove) {
                this.active[0].remove();
                this.active[1].remove();
                this.deactivate(this.active[0]);
                this.deactivate(this.active[1]);
            }
            return this;
        }
        this.deactivate(this.active[0]);
        this.deactivate(this.active[1]);
        this.activate(elm);
    } else {
        this.active[1] = elm;
    }
    this.emit("activate", elm);
};

Match.prototype.clicked = function (elm) {
    var self = this;
    elm.addEventListener("click", function () {
        self.activate(this);
    });
};

Match.prototype.addHandlers = function () {
    ElmSelect.call(this, this.ui.container.children, this.clicked);
};

Match.prototype.render = function (clear) {
    var self = this
      , cPos = {
            x: 0
          , y: 0
          , cX: 0
          , cY: 0
        }
      ;

    if (clear) {
       self.clear();
    }

    self.shuffle();
    self.items = self.data.slice(0, this.blocks_count / 2);

    IterateObject(self.items, function (cData, id) {
        for (var newElm, frontElm, backElm, i = 0; i < 2; ++i) {
            newElm = document.createElement("div");
            newElm.setAttribute("data-pattern", id);

            frontElm = document.createElement("div");
            frontElm.classList.add("front");

            backElm = document.createElement("div");
            backElm.classList.add("back");

            newElm.appendChild(frontElm);
            newElm.appendChild(backElm);

            frontElm.innerHTML = Barbe(self.ui.template, cData);

            self.ui.items.push({ element: newElm, data: cData, duplicate: !!i });
            self.emit("render", newElm, cData, i);
        }
    });

    self.shuffle(self.ui.items);

    self.ui.container.innerHTML = self.ui.items.map(function (c) {

        if (cPos.cY === self.options.size.y) {
            return "";
        }

        if (cPos.cX === self.options.size.x) {
            cPos.y += self.options.step.y;
            cPos.x = 0;
            cPos.cX = 0;
            ++cPos.cY;
            if (cPos.cY === self.options.size.y) {
                return "";
            }
        }

        c.element.style.top = cPos.y + "px";
        c.element.style.left = cPos.x + "px";

        cPos.x += self.options.step.x;
        ++cPos.cX;
        return c.element.outerHTML;
    }).join("");

    self.addHandlers();
};

Match.prototype.start = function () {
    var self = this;
    self.render(true);
};

module.exports = Match;
<|endoftext|>


<commit_before>var BloggifyLib = module.exports = {};

var _cache = {};

BloggifyLib.clearCache = function (options) {

    if (options && options.root) {
        _cache.APP_ROOT = options.root;
    } else {
        options = {
            root: _cache.APP_ROOT
        };
    }

    // Require config
    var Config = global.Config = Utils.requireNoCache(options.root + "/config");

    // Set log level
    Debug._config.logLevel = Config.logLevel;

    // start parsing paths
    Utils.parsePaths(Config.site.paths, ["parsed"]);

    // Attach core pages
    var allPages = Utils.cloneObject(Config.site.parsed.roots.pages)
      , pagesObj = Config.site.parsed.roots.pages = {}
      ;

    for (var i = 0, cPage; i < allPages.length; ++i) {
        cPage = allPages[i];
        pagesObj[cPage.path] = cPage;
    }

    Config.site.parsed.roots.pages["/login"] = {
        url: "/template/core/html/login.html"
      , visible: false
      , slug: "login"
    };

    Config.site.parsed.roots.pages["/blog"] = {
        url: "/template/core/html/blog.html"
      , label: "Blog"
      , order: 19
      , slug: "blog"
    };

    Config.site.parsed.roots.pages["/admin"] = {
        url: "/template/core/html/admin/index.html"
      , label: "Admin"
      , order: 21
      , loggedIn: true
      , slug: "admin"
    };

    Config.site.parsed.roots.pages["/admin/posts"] = {
        url: "/template/core/html/admin/posts.html"
      , loggedIn: true
      , slug: "admin-posts"
      , wrap: false
    };

    // Attach error pages
    for (var err in Config.errorPages) {
        Config.site.parsed.roots.pages["/" + err] = Config.errorPages[err];
    }

    // Statique config
    Statique
        .server({ root: options.root + Config.site.path })
        .setRoutes(Config.site.parsed.roots.pages)
        .setErrors(Config.errorPages)
      ;
};

/**
 * start
 *
 * @name start
 * @function
 * @param {Object} options The options object containing the following fields:
 *  - root: the bloggify root directory
 * @return
 */
BloggifyLib.start = function (options) {

    // Clear cache
    BloggifyLib.clearCache(options);

    // Handle uncaught exceptions
    if (Config.logLevel < 4) {
        process.on("uncaughtException", function (err) {
            Debug.log(err, "error");
        });
    }

    // Output
    Debug.log("Started Bloggify platform", "info");
};
<commit_msg>Add new post page<commit_after>var BloggifyLib = module.exports = {};

var _cache = {};

BloggifyLib.clearCache = function (options) {

    if (options && options.root) {
        _cache.APP_ROOT = options.root;
    } else {
        options = {
            root: _cache.APP_ROOT
        };
    }

    // Require config
    var Config = global.Config = Utils.requireNoCache(options.root + "/config");

    // Set log level
    Debug._config.logLevel = Config.logLevel;

    // start parsing paths
    Utils.parsePaths(Config.site.paths, ["parsed"]);

    // Attach core pages
    var allPages = Utils.cloneObject(Config.site.parsed.roots.pages)
      , pagesObj = Config.site.parsed.roots.pages = {}
      ;

    for (var i = 0, cPage; i < allPages.length; ++i) {
        cPage = allPages[i];
        pagesObj[cPage.path] = cPage;
    }

    Config.site.parsed.roots.pages["/login"] = {
        url: "/template/core/html/login.html"
      , visible: false
      , slug: "login"
    };

    Config.site.parsed.roots.pages["/blog"] = {
        url: "/template/core/html/blog.html"
      , label: "Blog"
      , order: 19
      , slug: "blog"
    };

    // Admin pages
    Config.site.parsed.roots.pages["/admin"] = {
        url: "/template/core/html/admin/index.html"
      , label: "Admin"
      , order: 21
      , loggedIn: true
      , slug: "admin"
    };

    Config.site.parsed.roots.pages["/admin/posts"] = {
        url: "/template/core/html/admin/posts.html"
      , loggedIn: true
      , slug: "admin-posts"
      , wrap: false
    };

    Config.site.parsed.roots.pages["/admin/posts/new"] = {
        url: "/template/core/html/admin/new-post.html"
      , loggedIn: true
      , slug: "new-post"
      , wrap: false
    };

    // Attach error pages
    for (var err in Config.errorPages) {
        Config.site.parsed.roots.pages["/" + err] = Config.errorPages[err];
    }

    // Statique config
    Statique
        .server({ root: options.root + Config.site.path })
        .setRoutes(Config.site.parsed.roots.pages)
        .setErrors(Config.errorPages)
      ;
};

/**
 * start
 *
 * @name start
 * @function
 * @param {Object} options The options object containing the following fields:
 *  - root: the bloggify root directory
 * @return
 */
BloggifyLib.start = function (options) {

    // Clear cache
    BloggifyLib.clearCache(options);

    // Handle uncaught exceptions
    if (Config.logLevel < 4) {
        process.on("uncaughtException", function (err) {
            Debug.log(err, "error");
        });
    }

    // Output
    Debug.log("Started Bloggify platform", "info");
};
<|endoftext|>


<commit_before>// Create a range object for efficently rendering strings to elements.
var range;

function empty(o) {
    for (var k in o) {
        if (o.hasOwnProperty(k)) {
            return false;
        }
    }

    return true;
}
function toElement(str) {
    if (!range && document.createRange) {
        range = document.createRange();
        range.selectNode(document.body);
    }

    var fragment;
    if (range && range.createContextualFragment) {
        fragment = range.createContextualFragment(str);
    } else {
        fragment = document.createElement('body');
        fragment.innerHTML = str;
    }
    return fragment.childNodes[0];
}

var specialElHandlers = {
    /**
     * Needed for IE. Apparently IE doesn't think
     * that "selected" is an attribute when reading
     * over the attributes using selectEl.attributes
     */
    OPTION: function(fromEl, toEl) {
        if ((fromEl.selected = toEl.selected)) {
            fromEl.setAttribute('selected', '');
        } else {
            fromEl.removeAttribute('selected', '');
        }
    },
    /**
     * The "value" attribute is special for the <input> element
     * since it sets the initial value. Changing the "value"
     * attribute without changing the "value" property will have
     * no effect since it is only used to the set the initial value.
     * Similar for the "checked" attribute.
     */
    INPUT: function(fromEl, toEl) {
        fromEl.checked = toEl.checked;

        if (fromEl.value != toEl.value) {
            fromEl.value = toEl.value;
        }

        if (!toEl.hasAttribute('checked')) {
            fromEl.removeAttribute('checked');
        }

        if (!toEl.hasAttribute('value')) {
            fromEl.removeAttribute('value');
        }
    },

    TEXTAREA: function(fromEl, toEl) {
        var newValue = toEl.value;
        if (fromEl.value != newValue) {
            fromEl.value = newValue;
        }

        if (fromEl.firstChild) {
            fromEl.firstChild.nodeValue = newValue;
        }
    }
};

function noop() {}

/**
 * Loop over all of the attributes on the target node and make sure the
 * original DOM node has the same attributes. If an attribute
 * found on the original node is not on the new node then remove it from
 * the original node
 * @param  {HTMLElement} fromNode
 * @param  {HTMLElement} toNode
 */
function morphAttrs(fromNode, toNode) {
    var attrs = toNode.attributes;
    var i;
    var attr;
    var attrName;
    var attrValue;
    var foundAttrs = {};

    for (i=attrs.length-1; i>=0; i--) {
        attr = attrs[i];
        if (attr.specified !== false) {
            attrName = attr.name;
            attrValue = attr.value;
            foundAttrs[attrName] = true;

            if (fromNode.getAttribute(attrName) !== attrValue) {
                fromNode.setAttribute(attrName, attrValue);
            }
        }
    }

    // Delete any extra attributes found on the original DOM element that weren't
    // found on the target element.
    attrs = fromNode.attributes;

    for (i=attrs.length-1; i>=0; i--) {
        attr = attrs[i];
        if (attr.specified !== false) {
            attrName = attr.name;
            if (!foundAttrs.hasOwnProperty(attrName)) {
                fromNode.removeAttribute(attrName);
            }
        }
    }
}

/**
 * Copies the children of one DOM element to another DOM element
 */
function moveChildren(fromEl, toEl) {
    var curChild = fromEl.firstChild;
    while(curChild) {
        var nextChild = curChild.nextSibling;
        toEl.appendChild(curChild);
        curChild = nextChild;
    }
    return toEl;
}

function defaultGetNodeKey(node) {
    return node.id;
}

function morphdom(fromNode, toNode, options) {
    if (!options) {
        options = {};
    }

    if (typeof toNode === 'string') {
        toNode = toElement(toNode);
    }

    var savedEls = {}; // Used to save off DOM elements with IDs
    var unmatchedEls = {};
    var getNodeKey = options.getNodeKey || defaultGetNodeKey;
    var onNodeDiscarded = options.onNodeDiscarded || noop;
    var onBeforeMorphEl = options.onBeforeMorphEl || noop;
    var onBeforeMorphElChildren = options.onBeforeMorphElChildren || noop;
    var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
    var childrenOnly = options.childrenOnly === true;
    var movedEls = [];

    function removeNodeHelper(node, nestedInSavedEl) {
        var id = getNodeKey(node);
        // If the node has an ID then save it off since we will want
        // to reuse it in case the target DOM tree has a DOM element
        // with the same ID
        if (id) {
            savedEls[id] = node;
        } else if (!nestedInSavedEl) {
            // If we are not nested in a saved element then we know that this node has been
            // completely discarded and will not exist in the final DOM.
            onNodeDiscarded(node);
        }

        if (node.nodeType === 1) {
            var curChild = node.firstChild;
            while(curChild) {
                removeNodeHelper(curChild, nestedInSavedEl || id);
                curChild = curChild.nextSibling;
            }
        }
    }

    function walkDiscardedChildNodes(node) {
        if (node.nodeType === 1) {
            var curChild = node.firstChild;
            while(curChild) {

                if (!getNodeKey(curChild)) {
                    // We only want to handle nodes that don't have an ID to avoid double
                    // walking the same saved element.

                    onNodeDiscarded(curChild);

                    // Walk recursively
                    walkDiscardedChildNodes(curChild);
                }

                curChild = curChild.nextSibling;
            }
        }
    }

    function removeNode(node, parentNode, alreadyVisited) {
        if (onBeforeNodeDiscarded(node) === false) {
            return;
        }

        parentNode.removeChild(node);
        if (alreadyVisited) {
            if (!getNodeKey(node)) {
                onNodeDiscarded(node);
                walkDiscardedChildNodes(node);
            }
        } else {
            removeNodeHelper(node);
        }
    }

    function morphEl(fromEl, toEl, alreadyVisited, childrenOnly) {
        var toElKey = getNodeKey(toEl);
        if (toElKey) {
            // If an element with an ID is being morphed then it is will be in the final
            // DOM so clear it out of the saved elements collection
            delete savedEls[toElKey];
        }

        if (!childrenOnly) {
            if (onBeforeMorphEl(fromEl, toEl) === false) {
                return;
            }

            morphAttrs(fromEl, toEl);

            if (onBeforeMorphElChildren(fromEl, toEl) === false) {
                return;
            }
        }

        if (fromEl.tagName != 'TEXTAREA') {
            var curToNodeChild = toEl.firstChild;
            var curFromNodeChild = fromEl.firstChild;
            var curToNodeId;

            var fromNextSibling;
            var toNextSibling;
            var savedEl;
            var unmatchedEl;

            outer: while(curToNodeChild) {
                toNextSibling = curToNodeChild.nextSibling;
                curToNodeId = getNodeKey(curToNodeChild);

                while(curFromNodeChild) {
                    var curFromNodeId = getNodeKey(curFromNodeChild);
                    fromNextSibling = curFromNodeChild.nextSibling;

                    if (!alreadyVisited) {
                        if (curFromNodeId && (unmatchedEl = unmatchedEls[curFromNodeId])) {
                            unmatchedEl.parentNode.replaceChild(curFromNodeChild, unmatchedEl);
                            morphEl(curFromNodeChild, unmatchedEl, alreadyVisited);
                            curFromNodeChild = fromNextSibling;
                            continue;
                        }
                    }

                    var curFromNodeType = curFromNodeChild.nodeType;

                    if (curFromNodeType === curToNodeChild.nodeType) {
                        var isCompatible = false;

                        if (curFromNodeType === 1) { // Both nodes being compared are Element nodes
                            if (curFromNodeChild.tagName === curToNodeChild.tagName) {
                                // We have compatible DOM elements
                                if (curFromNodeId || curToNodeId) {
                                    // If either DOM element has an ID then we handle
                                    // those differently since we want to match up
                                    // by ID
                                    if (curToNodeId === curFromNodeId) {
                                        isCompatible = true;
                                    }
                                } else {
                                    isCompatible = true;
                                }
                            }

                            if (isCompatible) {
                                // We found compatible DOM elements so transform the current "from" node
                                // to match the current target DOM node.
                                morphEl(curFromNodeChild, curToNodeChild, alreadyVisited);
                            }
                        } else if (curFromNodeType === 3) { // Both nodes being compared are Text nodes
                            isCompatible = true;
                            // Simply update nodeValue on the original node to change the text value
                            curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
                        }

                        if (isCompatible) {
                            curToNodeChild = toNextSibling;
                            curFromNodeChild = fromNextSibling;
                            continue outer;
                        }
                    }

                    // No compatible match so remove the old node from the DOM and continue trying
                    // to find a match in the original DOM
                    removeNode(curFromNodeChild, fromEl, alreadyVisited);
                    curFromNodeChild = fromNextSibling;
                }

                if (curToNodeId) {
                    if ((savedEl = savedEls[curToNodeId])) {
                        morphEl(savedEl, curToNodeChild, true);
                        curToNodeChild = savedEl; // We want to append the saved element instead
                    } else {
                        // The current DOM element in the target tree has an ID
                        // but we did not find a match in any of the corresponding
                        // siblings. We just put the target element in the old DOM tree
                        // but if we later find an element in the old DOM tree that has
                        // a matching ID then we will replace the target element
                        // with the corresponding old element and morph the old element
                        unmatchedEls[curToNodeId] = curToNodeChild;
                    }
                }

                // If we got this far then we did not find a candidate match for our "to node"
                // and we exhausted all of the children "from" nodes. Therefore, we will just
                // append the current "to node" to the end
                fromEl.appendChild(curToNodeChild);

                if (curToNodeChild.nodeType === 1 && (curToNodeId || curToNodeChild.firstChild)) {
                    // The element that was just added to the original DOM may have
                    // some nested elements with a key/ID that needs to be matched up
                    // with other elements. We'll add the element to a list so that we
                    // can later process the nested elements if there are any unmatched
                    // keyed elements that were discarded
                    movedEls.push(curToNodeChild);
                }

                curToNodeChild = toNextSibling;
                curFromNodeChild = fromNextSibling;
            }

            // We have processed all of the "to nodes". If curFromNodeChild is non-null then
            // we still have some from nodes left over that need to be removed
            while(curFromNodeChild) {
                fromNextSibling = curFromNodeChild.nextSibling;
                removeNode(curFromNodeChild, fromEl, alreadyVisited);
                curFromNodeChild = fromNextSibling;
            }
        }

        var specialElHandler = specialElHandlers[fromEl.tagName];
        if (specialElHandler) {
            specialElHandler(fromEl, toEl);
        }
    } // END: morphEl(...)

    var morphedNode = fromNode;
    var morphedNodeType = morphedNode.nodeType;
    var toNodeType = toNode.nodeType;

    if (!childrenOnly) {
        // Handle the case where we are given two DOM nodes that are not
        // compatible (e.g. <div> --> <span> or <div> --> TEXT)
        if (morphedNodeType === 1) {
            if (toNodeType === 1) {
                if (fromNode.tagName !== toNode.tagName) {
                    onNodeDiscarded(fromNode);
                    morphedNode = moveChildren(fromNode, document.createElement(toNode.tagName));
                }
            } else {
                // Going from an element node to a text node
                morphedNode = toNode;
            }
        } else if (morphedNodeType === 3) { // Text node
            if (toNodeType === 3) {
                morphedNode.nodeValue = toNode.nodeValue;
                return morphedNode;
            } else {
                // Text node to something else
                morphedNode = toNode;
            }
        }
    }

    if (morphedNode === toNode) {
        // The "to node" was not compatible with the "from node"
        // so we had to toss out the "from node" and use the "to node"
        onNodeDiscarded(fromNode);
    } else {
        morphEl(morphedNode, toNode, false, childrenOnly);

        /**
         * What we will do here is walk the tree for the DOM element
         * that was moved from the target DOM tree to the original
         * DOM tree and we will look for keyed elements that could
         * be matched to keyed elements that were earlier discarded.
         * If we find a match then we will move the saved element
         * into the final DOM tree
         */
        var handleMovedEl = function(el) {
            var curChild = el.firstChild;
            while(curChild) {
                var nextSibling = curChild.nextSibling;

                var key = getNodeKey(curChild);
                if (key) {
                    var savedEl = savedEls[key];
                    if (savedEl && (curChild.tagName === savedEl.tagName)) {
                        curChild.parentNode.replaceChild(savedEl, curChild);
                        morphEl(savedEl, curChild, true /* already visited the saved el tree */);
                        curChild = nextSibling;
                        if (empty(savedEls)) {
                            return false;
                        }
                        continue;
                    }
                }

                if (curChild.nodeType === 1) {
                    handleMovedEl(curChild);
                }

                curChild = nextSibling;
            }
        };

        // The loop below is used to possibly match up any discarded
        // elements in the original DOM tree with elemenets from the
        // target tree that were moved over without visiting their
        // children
        if (!empty(savedEls)) {
            handleMovedElsLoop:
            while (movedEls.length) {
                var movedElsTemp = movedEls;
                movedEls = [];
                for (var i=0; i<movedElsTemp.length; i++) {
                    if (handleMovedEl(movedElsTemp[i]) === false) {
                        // There are no more unmatched elements so completely end
                        // the loop
                        break handleMovedElsLoop;
                    }
                }
            }
        }

        // Fire the "onNodeDiscarded" event for any saved elements
        // that never found a new home in the morphed DOM
        for (var savedElId in savedEls) {
            if (savedEls.hasOwnProperty(savedElId)) {
                var savedEl = savedEls[savedElId];
                onNodeDiscarded(savedEl);
                walkDiscardedChildNodes(savedEl);
            }
        }
    }

    if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
        // If we had to swap out the from node with a new node because the old
        // node was not compatible with the target node then we need to
        // replace the old DOM node in the original DOM tree. This is only
        // possible if the original DOM node was part of a DOM tree which
        // we know is the case if it has a parent node.
        fromNode.parentNode.replaceChild(morphedNode, fromNode);
    }

    return morphedNode;
}

module.exports = morphdom;
<commit_msg>Provide a fallback for `hasAttribute` when it's not available.<commit_after>// Create a range object for efficently rendering strings to elements.
var range;

function empty(o) {
    for (var k in o) {
        if (o.hasOwnProperty(k)) {
            return false;
        }
    }

    return true;
}
function toElement(str) {
    if (!range && document.createRange) {
        range = document.createRange();
        range.selectNode(document.body);
    }

    var fragment;
    if (range && range.createContextualFragment) {
        fragment = range.createContextualFragment(str);
    } else {
        fragment = document.createElement('body');
        fragment.innerHTML = str;
    }
    return fragment.childNodes[0];
}

var specialElHandlers = {
    /**
     * Needed for IE. Apparently IE doesn't think
     * that "selected" is an attribute when reading
     * over the attributes using selectEl.attributes
     */
    OPTION: function(fromEl, toEl) {
        if ((fromEl.selected = toEl.selected)) {
            fromEl.setAttribute('selected', '');
        } else {
            fromEl.removeAttribute('selected', '');
        }
    },
    /**
     * The "value" attribute is special for the <input> element
     * since it sets the initial value. Changing the "value"
     * attribute without changing the "value" property will have
     * no effect since it is only used to the set the initial value.
     * Similar for the "checked" attribute.
     */
    INPUT: function(fromEl, toEl) {
        var hasCheckedAttribute = false;
        var hasValueAttribute = false;

        fromEl.checked = toEl.checked;

        if (fromEl.value != toEl.value) {
            fromEl.value = toEl.value;
        }

        if (toEl.hasAttribute) {
            hasCheckedAttribute = toEl.hasAttribute('checked');
            hasValueAttribute = toEl.hasAttribute('value');
        }
        else {
            hasCheckedAttribute = toEl.getAttribute('checked');
            hasValueAttribute = toEl.getAttribute('value');
        }

        if (!hasCheckedAttribute) {
            fromEl.removeAttribute('checked');
        }

        if (!hasValueAttribute) {
            fromEl.removeAttribute('value');
        }
    },

    TEXTAREA: function(fromEl, toEl) {
        var newValue = toEl.value;
        if (fromEl.value != newValue) {
            fromEl.value = newValue;
        }

        if (fromEl.firstChild) {
            fromEl.firstChild.nodeValue = newValue;
        }
    }
};

function noop() {}

/**
 * Loop over all of the attributes on the target node and make sure the
 * original DOM node has the same attributes. If an attribute
 * found on the original node is not on the new node then remove it from
 * the original node
 * @param  {HTMLElement} fromNode
 * @param  {HTMLElement} toNode
 */
function morphAttrs(fromNode, toNode) {
    var attrs = toNode.attributes;
    var i;
    var attr;
    var attrName;
    var attrValue;
    var foundAttrs = {};

    for (i=attrs.length-1; i>=0; i--) {
        attr = attrs[i];
        if (attr.specified !== false) {
            attrName = attr.name;
            attrValue = attr.value;
            foundAttrs[attrName] = true;

            if (fromNode.getAttribute(attrName) !== attrValue) {
                fromNode.setAttribute(attrName, attrValue);
            }
        }
    }

    // Delete any extra attributes found on the original DOM element that weren't
    // found on the target element.
    attrs = fromNode.attributes;

    for (i=attrs.length-1; i>=0; i--) {
        attr = attrs[i];
        if (attr.specified !== false) {
            attrName = attr.name;
            if (!foundAttrs.hasOwnProperty(attrName)) {
                fromNode.removeAttribute(attrName);
            }
        }
    }
}

/**
 * Copies the children of one DOM element to another DOM element
 */
function moveChildren(fromEl, toEl) {
    var curChild = fromEl.firstChild;
    while(curChild) {
        var nextChild = curChild.nextSibling;
        toEl.appendChild(curChild);
        curChild = nextChild;
    }
    return toEl;
}

function defaultGetNodeKey(node) {
    return node.id;
}

function morphdom(fromNode, toNode, options) {
    if (!options) {
        options = {};
    }

    if (typeof toNode === 'string') {
        toNode = toElement(toNode);
    }

    var savedEls = {}; // Used to save off DOM elements with IDs
    var unmatchedEls = {};
    var getNodeKey = options.getNodeKey || defaultGetNodeKey;
    var onNodeDiscarded = options.onNodeDiscarded || noop;
    var onBeforeMorphEl = options.onBeforeMorphEl || noop;
    var onBeforeMorphElChildren = options.onBeforeMorphElChildren || noop;
    var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
    var childrenOnly = options.childrenOnly === true;
    var movedEls = [];

    function removeNodeHelper(node, nestedInSavedEl) {
        var id = getNodeKey(node);
        // If the node has an ID then save it off since we will want
        // to reuse it in case the target DOM tree has a DOM element
        // with the same ID
        if (id) {
            savedEls[id] = node;
        } else if (!nestedInSavedEl) {
            // If we are not nested in a saved element then we know that this node has been
            // completely discarded and will not exist in the final DOM.
            onNodeDiscarded(node);
        }

        if (node.nodeType === 1) {
            var curChild = node.firstChild;
            while(curChild) {
                removeNodeHelper(curChild, nestedInSavedEl || id);
                curChild = curChild.nextSibling;
            }
        }
    }

    function walkDiscardedChildNodes(node) {
        if (node.nodeType === 1) {
            var curChild = node.firstChild;
            while(curChild) {

                if (!getNodeKey(curChild)) {
                    // We only want to handle nodes that don't have an ID to avoid double
                    // walking the same saved element.

                    onNodeDiscarded(curChild);

                    // Walk recursively
                    walkDiscardedChildNodes(curChild);
                }

                curChild = curChild.nextSibling;
            }
        }
    }

    function removeNode(node, parentNode, alreadyVisited) {
        if (onBeforeNodeDiscarded(node) === false) {
            return;
        }

        parentNode.removeChild(node);
        if (alreadyVisited) {
            if (!getNodeKey(node)) {
                onNodeDiscarded(node);
                walkDiscardedChildNodes(node);
            }
        } else {
            removeNodeHelper(node);
        }
    }

    function morphEl(fromEl, toEl, alreadyVisited, childrenOnly) {
        var toElKey = getNodeKey(toEl);
        if (toElKey) {
            // If an element with an ID is being morphed then it is will be in the final
            // DOM so clear it out of the saved elements collection
            delete savedEls[toElKey];
        }

        if (!childrenOnly) {
            if (onBeforeMorphEl(fromEl, toEl) === false) {
                return;
            }

            morphAttrs(fromEl, toEl);

            if (onBeforeMorphElChildren(fromEl, toEl) === false) {
                return;
            }
        }

        if (fromEl.tagName != 'TEXTAREA') {
            var curToNodeChild = toEl.firstChild;
            var curFromNodeChild = fromEl.firstChild;
            var curToNodeId;

            var fromNextSibling;
            var toNextSibling;
            var savedEl;
            var unmatchedEl;

            outer: while(curToNodeChild) {
                toNextSibling = curToNodeChild.nextSibling;
                curToNodeId = getNodeKey(curToNodeChild);

                while(curFromNodeChild) {
                    var curFromNodeId = getNodeKey(curFromNodeChild);
                    fromNextSibling = curFromNodeChild.nextSibling;

                    if (!alreadyVisited) {
                        if (curFromNodeId && (unmatchedEl = unmatchedEls[curFromNodeId])) {
                            unmatchedEl.parentNode.replaceChild(curFromNodeChild, unmatchedEl);
                            morphEl(curFromNodeChild, unmatchedEl, alreadyVisited);
                            curFromNodeChild = fromNextSibling;
                            continue;
                        }
                    }

                    var curFromNodeType = curFromNodeChild.nodeType;

                    if (curFromNodeType === curToNodeChild.nodeType) {
                        var isCompatible = false;

                        if (curFromNodeType === 1) { // Both nodes being compared are Element nodes
                            if (curFromNodeChild.tagName === curToNodeChild.tagName) {
                                // We have compatible DOM elements
                                if (curFromNodeId || curToNodeId) {
                                    // If either DOM element has an ID then we handle
                                    // those differently since we want to match up
                                    // by ID
                                    if (curToNodeId === curFromNodeId) {
                                        isCompatible = true;
                                    }
                                } else {
                                    isCompatible = true;
                                }
                            }

                            if (isCompatible) {
                                // We found compatible DOM elements so transform the current "from" node
                                // to match the current target DOM node.
                                morphEl(curFromNodeChild, curToNodeChild, alreadyVisited);
                            }
                        } else if (curFromNodeType === 3) { // Both nodes being compared are Text nodes
                            isCompatible = true;
                            // Simply update nodeValue on the original node to change the text value
                            curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
                        }

                        if (isCompatible) {
                            curToNodeChild = toNextSibling;
                            curFromNodeChild = fromNextSibling;
                            continue outer;
                        }
                    }

                    // No compatible match so remove the old node from the DOM and continue trying
                    // to find a match in the original DOM
                    removeNode(curFromNodeChild, fromEl, alreadyVisited);
                    curFromNodeChild = fromNextSibling;
                }

                if (curToNodeId) {
                    if ((savedEl = savedEls[curToNodeId])) {
                        morphEl(savedEl, curToNodeChild, true);
                        curToNodeChild = savedEl; // We want to append the saved element instead
                    } else {
                        // The current DOM element in the target tree has an ID
                        // but we did not find a match in any of the corresponding
                        // siblings. We just put the target element in the old DOM tree
                        // but if we later find an element in the old DOM tree that has
                        // a matching ID then we will replace the target element
                        // with the corresponding old element and morph the old element
                        unmatchedEls[curToNodeId] = curToNodeChild;
                    }
                }

                // If we got this far then we did not find a candidate match for our "to node"
                // and we exhausted all of the children "from" nodes. Therefore, we will just
                // append the current "to node" to the end
                fromEl.appendChild(curToNodeChild);

                if (curToNodeChild.nodeType === 1 && (curToNodeId || curToNodeChild.firstChild)) {
                    // The element that was just added to the original DOM may have
                    // some nested elements with a key/ID that needs to be matched up
                    // with other elements. We'll add the element to a list so that we
                    // can later process the nested elements if there are any unmatched
                    // keyed elements that were discarded
                    movedEls.push(curToNodeChild);
                }

                curToNodeChild = toNextSibling;
                curFromNodeChild = fromNextSibling;
            }

            // We have processed all of the "to nodes". If curFromNodeChild is non-null then
            // we still have some from nodes left over that need to be removed
            while(curFromNodeChild) {
                fromNextSibling = curFromNodeChild.nextSibling;
                removeNode(curFromNodeChild, fromEl, alreadyVisited);
                curFromNodeChild = fromNextSibling;
            }
        }

        var specialElHandler = specialElHandlers[fromEl.tagName];
        if (specialElHandler) {
            specialElHandler(fromEl, toEl);
        }
    } // END: morphEl(...)

    var morphedNode = fromNode;
    var morphedNodeType = morphedNode.nodeType;
    var toNodeType = toNode.nodeType;

    if (!childrenOnly) {
        // Handle the case where we are given two DOM nodes that are not
        // compatible (e.g. <div> --> <span> or <div> --> TEXT)
        if (morphedNodeType === 1) {
            if (toNodeType === 1) {
                if (fromNode.tagName !== toNode.tagName) {
                    onNodeDiscarded(fromNode);
                    morphedNode = moveChildren(fromNode, document.createElement(toNode.tagName));
                }
            } else {
                // Going from an element node to a text node
                morphedNode = toNode;
            }
        } else if (morphedNodeType === 3) { // Text node
            if (toNodeType === 3) {
                morphedNode.nodeValue = toNode.nodeValue;
                return morphedNode;
            } else {
                // Text node to something else
                morphedNode = toNode;
            }
        }
    }

    if (morphedNode === toNode) {
        // The "to node" was not compatible with the "from node"
        // so we had to toss out the "from node" and use the "to node"
        onNodeDiscarded(fromNode);
    } else {
        morphEl(morphedNode, toNode, false, childrenOnly);

        /**
         * What we will do here is walk the tree for the DOM element
         * that was moved from the target DOM tree to the original
         * DOM tree and we will look for keyed elements that could
         * be matched to keyed elements that were earlier discarded.
         * If we find a match then we will move the saved element
         * into the final DOM tree
         */
        var handleMovedEl = function(el) {
            var curChild = el.firstChild;
            while(curChild) {
                var nextSibling = curChild.nextSibling;

                var key = getNodeKey(curChild);
                if (key) {
                    var savedEl = savedEls[key];
                    if (savedEl && (curChild.tagName === savedEl.tagName)) {
                        curChild.parentNode.replaceChild(savedEl, curChild);
                        morphEl(savedEl, curChild, true /* already visited the saved el tree */);
                        curChild = nextSibling;
                        if (empty(savedEls)) {
                            return false;
                        }
                        continue;
                    }
                }

                if (curChild.nodeType === 1) {
                    handleMovedEl(curChild);
                }

                curChild = nextSibling;
            }
        };

        // The loop below is used to possibly match up any discarded
        // elements in the original DOM tree with elemenets from the
        // target tree that were moved over without visiting their
        // children
        if (!empty(savedEls)) {
            handleMovedElsLoop:
            while (movedEls.length) {
                var movedElsTemp = movedEls;
                movedEls = [];
                for (var i=0; i<movedElsTemp.length; i++) {
                    if (handleMovedEl(movedElsTemp[i]) === false) {
                        // There are no more unmatched elements so completely end
                        // the loop
                        break handleMovedElsLoop;
                    }
                }
            }
        }

        // Fire the "onNodeDiscarded" event for any saved elements
        // that never found a new home in the morphed DOM
        for (var savedElId in savedEls) {
            if (savedEls.hasOwnProperty(savedElId)) {
                var savedEl = savedEls[savedElId];
                onNodeDiscarded(savedEl);
                walkDiscardedChildNodes(savedEl);
            }
        }
    }

    if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
        // If we had to swap out the from node with a new node because the old
        // node was not compatible with the target node then we need to
        // replace the old DOM node in the original DOM tree. This is only
        // possible if the original DOM node was part of a DOM tree which
        // we know is the case if it has a parent node.
        fromNode.parentNode.replaceChild(morphedNode, fromNode);
    }

    return morphedNode;
}

module.exports = morphdom;
<|endoftext|>


<commit_before>#!/usr/bin/env node
/**
 * Created by apizzimenti on 1/1/17.
 */

var weather = require("./weather"),
    tools = require("./tools"),

    min = require("minimist")(process.argv.slice(1)),
    chalk = require("chalk"),

    help = tools.Help,
    Args = tools.Args,

    Help = new help(
        "cli-weather",
        "Retrieves weather for your current location or an input location.",
        {
            "celsius": "-c | --celsius → Change all units to si units (Celsius degrees/meters per second).",
            "help": "-h | --help → Display this help page.",
            "address": "-a [address] | --address=[address] → Retrieve the weather for the provided location.",
            "zip": "-z [zip code] | --zip=[zip code] → Retrieve the weather for the provided zip code.",
            "verbose": "-v | --verbose → Show status messages while retrieving your weather."
        }
    ),

    args = new Args(min, {
        "address": ["a", "address"],
        "help": ["h", "help"],
        "celsius": ["c", "celsius"],
        "zip": ["z", "zip"],
        "verbose": ["v", "verbose"]
    }),

    auto = !(args.get("address") || args.get("zip"));

if (args.get("help")) {
    Help.display();
}

if (auto) {
    weather.ip(args, weather.ip_location);
} else if (!auto) {
    weather.p_location(args, weather.weather);
}

module.exports = {
    ip: weather.ip,
    location: weather.location
};
<commit_msg>require config_weather<commit_after>#!/usr/bin/env node
/**
 * Created by apizzimenti on 1/1/17.
 */

var weather = require("./weather");

weather.config_weather();

module.exports = {
    weather: weather
};
<|endoftext|>