<commit_before>'use strict';

// --- Dependencies ---
var debug      = require('debug')('arkivo:sufia');
var assert     = require('assert');
var inherits   = require('util').inherits;

var HTTPClient = require('./http');
var SufiaItem  = require('./item');

var slice      = Array.prototype.slice;
var properties = Object.defineProperties;

var config = require('arkivo/lib/config');
var common = require('arkivo/lib/common');
var extend = common.extend;
var pick   = common.pick;

var B      = require('bluebird');
var co     = B.coroutine;

/**
 * @class SufiaClient
 */
function SufiaClient(options, sync) {
  assert(sync);
  assert(sync.subscription);

  var defaults = config.has('sufia')
    ? extend({}, SufiaClient.defaults, config.get('sufia'))
    : SufiaClient.defaults;

  options = options || {};

  options.base = options.base || defaults.base;
  options.mimetypes = defaults.mimetypes.slice();

  extend(options, {
    create: options.base + defaults.create,
    update: options.base + defaults.update,
    delete: options.base + defaults.delete
  });

  this.sync  = sync;

  this.debug('creating new client for %s...', options.base);

  HTTPClient.call(this, options);

  if (!sync.subscription.data.sufia) {
    this.debug('creating new id repository...');
    sync.subscription.data.sufia = {};
  }
}

inherits(SufiaClient, HTTPClient);

SufiaClient.defaults = {
  base: 'http://localhost:3000',

  create: '/api/items',
  update: '/api/items/:id',
  delete: '/api/items/:id',

  mimetypes: [
    'application/pdf'
  ]
};

properties(SufiaClient.prototype, {

  /**
   * @property registry
   * @type Object
   */
  registry: {
    get: function () {
      return this.sync.subscription.data.sufia;
    }
  },

  /**
   * @property deleted
   * @type Array
   */
  deleted: {
    get: function get$deleted() {
      var deleted = [], i, ii, key;

      for (i = 0, ii = this.sync.deleted.length; i < ii; ++i) {
        key = this.sync.deleted[i];

        if (this.registry[key])
          deleted.push(key);

      }

      return deleted;
    }
  },

  /**
   * @property created
   * @type Object
   */
  created: {
    get: function get$created() {
      return this.collect(this.sync.created);
    }
  },

  /**
   * @property updated
   * @type Object
   */
  updated: {
    get: function get$updated() {
      return this.collect(this.sync.updated);
    }
  }
});

/**
 * Delete the item with the given Sufia id.
 *
 * @method delete
 * @return {Promise}
 */
SufiaClient.prototype.delete = function (key) {
  var id = this.registry[key];

  if (!id)
    return this.debug('cannot delete "%s": id missing', key);

  return this
    .send('del', this.path('delete', { id: id }), pick(this.options, 'token'))

    .catch(function (error) {
      if (error.status !== 404) throw error;
    })

    .tap(function () {
      delete this.registry[key];
      this.debug('deleted "%s" successfully', key);
    });
};

/**
 * Create the given Sufia item associated to a Zotero key.
 *
 * @method create
 * @return {Promise}
 */
SufiaClient.prototype.create = function (key, item) {
  this.debug('creating item %s...', key);

  return this
    .send('post', this.path('create'), null, item)

    .tap(function (res) {
      var m = (/api\/items\/([^\/]+)/).exec(res.header.location);

      if (m) {
        this.registry[key] = m[1];
        this.debug('created item "%s" with id "%s"', key, m[1]);

      } else {
        this.debug('failed to extract id of created item "%s"', key);
      }
    });
};

/**
 * Update the given Sufai item associated to a Zotero key.
 *
 * @method update
 * @return {Promise}
 */
SufiaClient.prototype.update = function (key, item) {
  var id = this.registry[key];

  if (!id) return this.create(key, item);

  this.debug('updating item %s/%s...', key, id);

  return this
    .send('put', this.path('update', { id: id }), null, item)

    .tap(function () {
      this.debug('updated item "%s" with id "%s"', key, id);
    })

    .catch(function (error) {
      if (error.status !== 404) throw error;

      // Try to create the item if it does not yet exist!
      return this.create(key, item);
    });
};

/**
 * Downloads the item's attachment.
 * @method download
 * @return {Promise}
 */
SufiaClient.prototype.download = function (item) {
  this.debug('downloading attachment %s...', item.key);

  return this
    .sync
    .attachment(item)
    .get('data');
};

/**
 * Collect Zotero items which can be uploaded to Sufia/Hydra;
 * this includes only items with a usable single-file attachment.
 *
 * @method collect
 * @param {Array} keys The list of Zotero keys to look at.
 *
 * @return {Promise<Object>}
 *   The collection of Zotero key SufiaItem pairs.
 */
SufiaClient.prototype.collect = co(function* (keys) {
  var i, ii, item, child, data, collection = {};

  for (i = 0, ii = keys.length; i < ii; ++i) {
    try {
      item = this.expand(keys[i]);

      if (!item) {
        this.debug('cannot expand "%s": item missing', keys[i]);
        continue;
      }

      // Duplicate items are possible, because child items are
      // expanded to their parents; therefore, if a sync session
      // includes an item and one or more of its children, we
      // might process the item multiple times!
      if (collection[item.key]) continue;

      // Skip items without attachments!
      if (!item.children) continue;

      child = this.select(item.children);

      if (!child) {
        this.debug('skipping "%s": no suitable attachments found', item.key);
        continue;
      }

      data = yield this.download(child.key);

      collection[item.key] =
        new SufiaItem(this.options.token, item, child, data);

    } catch (error) {
      this.debug('failed to collect item: %s', error.message);
      debug(error.stack);

      continue;
    }
  }

  return collection;
});

/**
 * Selects the first suitable attachment item.
 *
 * @method select
 * @param {Array} items
 * @return {Object}
 */
SufiaClient.prototype.select = function (items) {
  if (!items) return undefined;
  if (!items.length) return undefined;

  var i, ii, item, next;

  for (i = 0, ii = items.length; i < ii; ++i) {
    next = items[i];

    if (next.data.itemType !== 'attachment')
      continue;

    if (next.data.linkMode !== 'imported_file')
      continue;

    if (this.options.mimetypes.indexOf(next.data.contentType) < 0)
      continue;

    if (item) {

      if (item.dateAdded < next.dateAdded) continue;

    }

    item = next;
  }

  return item;
};

/**
 * Returns the Zotero item for key; if the item has
 * a parent, returns parent item instead.
 *
 * @method expand
 * @private
 */
SufiaClient.prototype.expand = function (key) {
  var item = this.sync.items[key];

  if (item && item.data.parentItem)
    return this.expand(item.data.parentItem);

  return item;
};

SufiaClient.prototype.debug = function (message) {
  debug.apply(null, [
    '[%s] ' + message, this.sync.subscription.id
  ].concat(slice.call(arguments, 1)));

  return this;
};

// --- Helpers ---

// --- Exports ---
module.exports = SufiaClient;
<commit_msg>fix download<commit_after>'use strict';

// --- Dependencies ---
var debug      = require('debug')('arkivo:sufia');
var assert     = require('assert');
var inherits   = require('util').inherits;

var HTTPClient = require('./http');
var SufiaItem  = require('./item');

var slice      = Array.prototype.slice;
var properties = Object.defineProperties;

var config = require('arkivo/lib/config');
var common = require('arkivo/lib/common');
var extend = common.extend;
var pick   = common.pick;

var B      = require('bluebird');
var co     = B.coroutine;

/**
 * @class SufiaClient
 */
function SufiaClient(options, sync) {
  assert(sync);
  assert(sync.subscription);

  var defaults = config.has('sufia')
    ? extend({}, SufiaClient.defaults, config.get('sufia'))
    : SufiaClient.defaults;

  options = options || {};

  options.base = options.base || defaults.base;
  options.mimetypes = defaults.mimetypes.slice();

  extend(options, {
    create: options.base + defaults.create,
    update: options.base + defaults.update,
    delete: options.base + defaults.delete
  });

  this.sync  = sync;

  this.debug('creating new client for %s...', options.base);

  HTTPClient.call(this, options);

  if (!sync.subscription.data.sufia) {
    this.debug('creating new id repository...');
    sync.subscription.data.sufia = {};
  }
}

inherits(SufiaClient, HTTPClient);

SufiaClient.defaults = {
  base: 'http://localhost:3000',

  create: '/api/items',
  update: '/api/items/:id',
  delete: '/api/items/:id',

  mimetypes: [
    'application/pdf'
  ]
};

properties(SufiaClient.prototype, {

  /**
   * @property registry
   * @type Object
   */
  registry: {
    get: function () {
      return this.sync.subscription.data.sufia;
    }
  },

  /**
   * @property deleted
   * @type Array
   */
  deleted: {
    get: function get$deleted() {
      var deleted = [], i, ii, key;

      for (i = 0, ii = this.sync.deleted.length; i < ii; ++i) {
        key = this.sync.deleted[i];

        if (this.registry[key])
          deleted.push(key);

      }

      return deleted;
    }
  },

  /**
   * @property created
   * @type Object
   */
  created: {
    get: function get$created() {
      return this.collect(this.sync.created);
    }
  },

  /**
   * @property updated
   * @type Object
   */
  updated: {
    get: function get$updated() {
      return this.collect(this.sync.updated);
    }
  }
});

/**
 * Delete the item with the given Sufia id.
 *
 * @method delete
 * @return {Promise}
 */
SufiaClient.prototype.delete = function (key) {
  var id = this.registry[key];

  if (!id)
    return this.debug('cannot delete "%s": id missing', key);

  return this
    .send('del', this.path('delete', { id: id }), pick(this.options, 'token'))

    .catch(function (error) {
      if (error.status !== 404) throw error;
    })

    .tap(function () {
      delete this.registry[key];
      this.debug('deleted "%s" successfully', key);
    });
};

/**
 * Create the given Sufia item associated to a Zotero key.
 *
 * @method create
 * @return {Promise}
 */
SufiaClient.prototype.create = function (key, item) {
  this.debug('creating item %s...', key);

  return this
    .send('post', this.path('create'), null, item)

    .tap(function (res) {
      var m = (/api\/items\/([^\/]+)/).exec(res.header.location);

      if (m) {
        this.registry[key] = m[1];
        this.debug('created item "%s" with id "%s"', key, m[1]);

      } else {
        this.debug('failed to extract id of created item "%s"', key);
      }
    });
};

/**
 * Update the given Sufai item associated to a Zotero key.
 *
 * @method update
 * @return {Promise}
 */
SufiaClient.prototype.update = function (key, item) {
  var id = this.registry[key];

  if (!id) return this.create(key, item);

  this.debug('updating item %s/%s...', key, id);

  return this
    .send('put', this.path('update', { id: id }), null, item)

    .tap(function () {
      this.debug('updated item "%s" with id "%s"', key, id);
    })

    .catch(function (error) {
      if (error.status !== 404) throw error;

      // Try to create the item if it does not yet exist!
      return this.create(key, item);
    });
};

/**
 * Downloads the item's attachment.
 * @method download
 * @return {Promise}
 */
SufiaClient.prototype.download = function (item) {
  this.debug('downloading attachment %s...', item.key);

  return this
    .sync
    .attachment(item)
    .get('data');
};

/**
 * Collect Zotero items which can be uploaded to Sufia/Hydra;
 * this includes only items with a usable single-file attachment.
 *
 * @method collect
 * @param {Array} keys The list of Zotero keys to look at.
 *
 * @return {Promise<Object>}
 *   The collection of Zotero key SufiaItem pairs.
 */
SufiaClient.prototype.collect = co(function* (keys) {
  var i, ii, item, child, data, collection = {};

  for (i = 0, ii = keys.length; i < ii; ++i) {
    try {
      item = this.expand(keys[i]);

      if (!item) {
        this.debug('cannot expand "%s": item missing', keys[i]);
        continue;
      }

      // Duplicate items are possible, because child items are
      // expanded to their parents; therefore, if a sync session
      // includes an item and one or more of its children, we
      // might process the item multiple times!
      if (collection[item.key]) continue;

      // Skip items without attachments!
      if (!item.children) continue;

      child = this.select(item.children);

      if (!child) {
        this.debug('skipping "%s": no suitable attachments found', item.key);
        continue;
      }

      data = yield this.download(child);

      collection[item.key] =
        new SufiaItem(this.options.token, item, child, data);

    } catch (error) {
      this.debug('failed to collect item: %s', error.message);
      debug(error.stack);

      continue;
    }
  }

  return collection;
});

/**
 * Selects the first suitable attachment item.
 *
 * @method select
 * @param {Array} items
 * @return {Object}
 */
SufiaClient.prototype.select = function (items) {
  if (!items) return undefined;
  if (!items.length) return undefined;

  var i, ii, item, next;

  for (i = 0, ii = items.length; i < ii; ++i) {
    next = items[i];

    if (next.data.itemType !== 'attachment')
      continue;

    if (next.data.linkMode !== 'imported_file')
      continue;

    if (this.options.mimetypes.indexOf(next.data.contentType) < 0)
      continue;

    if (item) {

      if (item.dateAdded < next.dateAdded) continue;

    }

    item = next;
  }

  return item;
};

/**
 * Returns the Zotero item for key; if the item has
 * a parent, returns parent item instead.
 *
 * @method expand
 * @private
 */
SufiaClient.prototype.expand = function (key) {
  var item = this.sync.items[key];

  if (item && item.data.parentItem)
    return this.expand(item.data.parentItem);

  return item;
};

SufiaClient.prototype.debug = function (message) {
  debug.apply(null, [
    '[%s] ' + message, this.sync.subscription.id
  ].concat(slice.call(arguments, 1)));

  return this;
};

// --- Helpers ---

// --- Exports ---
module.exports = SufiaClient;
<|endoftext|>


<commit_before>/* Jedi public API */

'use strict'

require('../lib/ometa-js')

var Parser = require('./parser').Parser
var transformer = require('./transformer')
var transpiler = {
	php5: require('./transpiler.php5').PHP5Transpiler,
	es5: require('./transpiler.es5').ES5Transpiler
}

var fs = require('fs'), path = require('path')
var http = require('http'), url = require('url')

var util = require('./util')

var Class = require('mmclass').Class
var FileCache = require('./Cache').FileCache

var ParserCache = Class.extend(FileCache)({
	content: function (file) {
		return Parser.match(file, 'load')
	}
})

var cache = new ParserCache()

function parseFile(filename) {
	return cache.get(path.resolve(filename))
}

function transform(tree, debug) {
	if (debug === undefined) debug = []
	var tree1 = tree
	if (debug[0]) util.dir(tree1)
	var tree2 = transformer.InstructionsProcessor.match(tree1, 'document')
	if (debug[1]) util.dir(tree2)
	var tree3 = transformer.TemplateMatcher.match(tree2, 'document')
	if (debug[2]) util.dir(tree3)
	var tree4 = transformer.Sorter.match(tree3, 'document')
	if (debug[3]) util.dir(tree4)
	return tree4
}

function compile(ast, target) {
	switch (target) {
		case 'php5': case 'php':
			return transpiler.php5.match(ast, 'document')
		case 'es5': case 'ecmascript':
		case 'js': case 'javascript':
			return transpiler.es5.match(ast, 'document')
		default:
			throw Error('Unknown target language: ' + target)
	}
}

function transpile(source, dest, lang, debug) {
	try {
		var tree = transform(parseFile(source), debug)
		fs.writeFileSync(dest, compile(tree, lang))
	} catch(e) {
		var info = e.stack || e.message || e
		console.error('Error: ', String(info))
		fs.writeFileSync(dest, info)
	}
}

function watch(source, dest, lang, debug) {
	//TODO: watch dependencies
	transpile(source, dest, lang, debug)
	fs.watch(source, function(evt, filename) {
		transpile(source, dest, lang, debug)
	})
}

function service(options) {
	//var watched = []

	http.createServer(function (req, res) {
		switch (req.method) {
			case 'GET':
				var f = path.join(options.base, url.parse(req.url).path)
				//if (watched.indexOf(path) >= 0)

				fs.exists(f, function(exists){
					if (!exists) {
						res.writeHead(404)
						res.end('file not exist\n')
					} else {
						var t0 = Date.now()
						options.lang.forEach(function(lang){
							transpile(f, f.replace(/\.jedi$/, '.' + lang), lang)
						})
						var t1 = Date.now()
						res.writeHead(200)
						res.end('transpiled in ' + (t1 - t0) + 'ms\n')
					}
				})

				//transpiler.watch(loc.pathname)
				break
			default:
				res.writeHead(405)
				res.end()
		}
	}).listen(options.port)

}

exports.parseFile = parseFile
//exports.transform = transform
//exports.compile = compile
exports.transpile = transpile
exports.watch = watch
exports.service = service<commit_msg>add isFile check<commit_after>/* Jedi public API */

'use strict'

require('../lib/ometa-js')

var Parser = require('./parser').Parser
var transformer = require('./transformer')
var transpiler = {
	php5: require('./transpiler.php5').PHP5Transpiler,
	es5: require('./transpiler.es5').ES5Transpiler
}

var fs = require('fs'), path = require('path')
var http = require('http'), url = require('url')

var util = require('./util')

var Class = require('mmclass').Class
var FileCache = require('./Cache').FileCache

var ParserCache = Class.extend(FileCache)({
	content: function (file) {
		return Parser.match(file, 'load')
	}
})

var cache = new ParserCache()

function parseFile(filename) {
	return cache.get(path.resolve(filename))
}

function transform(tree, debug) {
	if (debug === undefined) debug = []
	var tree1 = tree
	if (debug[0]) util.dir(tree1)
	var tree2 = transformer.InstructionsProcessor.match(tree1, 'document')
	if (debug[1]) util.dir(tree2)
	var tree3 = transformer.TemplateMatcher.match(tree2, 'document')
	if (debug[2]) util.dir(tree3)
	var tree4 = transformer.Sorter.match(tree3, 'document')
	if (debug[3]) util.dir(tree4)
	return tree4
}

function compile(ast, target) {
	switch (target) {
		case 'php5': case 'php':
			return transpiler.php5.match(ast, 'document')
		case 'es5': case 'ecmascript':
		case 'js': case 'javascript':
			return transpiler.es5.match(ast, 'document')
		default:
			throw Error('Unknown target language: ' + target)
	}
}

function transpile(source, dest, lang, debug) {
	try {
		var tree = transform(parseFile(source), debug)
		fs.writeFileSync(dest, compile(tree, lang))
	} catch(e) {
		var info = e.stack || e.message || e
		console.error('Error: ', String(info))
		fs.writeFileSync(dest, info)
	}
}

function watch(source, dest, lang, debug) {
	//TODO: watch dependencies
	transpile(source, dest, lang, debug)
	fs.watch(source, function(evt, filename) {
		transpile(source, dest, lang, debug)
	})
}

function service(options) {
	//var watched = []

	http.createServer(function (req, res) {

		switch (req.method) {
			case 'GET':
				var f = path.join(options.base, url.parse(req.url).path)
				//if (watched.indexOf(path) >= 0)

				fs.exists(f, function(exists){
					if (!exists) {
						send(404, 'file ' + f + ' not exist\n')
					} else {
						fs.stat(f, function(err, stats){
							if (stats.isFile()) {
								var t0 = Date.now()
								options.lang.forEach(function(lang){
									transpile(f, f.replace(/\.jedi$/, '.' + lang), lang)
								})
								var t1 = Date.now()
								send(200, 'transpiled in ' + (t1 - t0) + 'ms\n')
							} else {
								send(404, 'path ' + f + ' is not a file\n')
							}
						})
					}
				})

				//transpiler.watch(loc.pathname)
				break
			default:
				res.writeHead(405)
				res.end()
		}

		function send(status, message){
			res.writeHead(status)
			res.end(message)
			if (status >= 400) {
				console.error(message)
			} else {
				console.info(message)
			}
		}

	}).listen(options.port)

}

exports.parseFile = parseFile
//exports.transform = transform
//exports.compile = compile
exports.transpile = transpile
exports.watch = watch
exports.service = service<|endoftext|>


<commit_before>var _ = require('underscore'),

    isArray    = require('is/array'),
    isHtml     = require('is/html'),
    isString   = require('is/string'),
    isNodeList = require('is/nodeList'),
    isFunction = require('is/function'),
    isD        = require('is/d'),

    parser      = require('./modules/parser/parser'),
    utils       = require('./utils'),
    array       = require('./modules/array'),
    onready     = require('./modules/onready'),
    selectors   = require('./modules/selectors'),
    transversal = require('./modules/transversal'),
    dimensions  = require('./modules/dimensions'),
    manip       = require('./modules/manip'),
    css         = require('./modules/css'),
    attr        = require('./modules/attr'),
    prop        = require('./modules/prop'),
    val         = require('./modules/val'),
    position    = require('./modules/position'),
    classes     = require('./modules/classes'),
    data        = require('./modules/data'),
    events      = require('./modules/event/api'),
    eventObj    = require('./modules/event/event'),
    deferred    = require('./modules/Deferred/Deferred'),
    when        = require('./modules/Deferred/when'),

    xaja        = require('xaja-js');

// Store previous reference
var _prevD = window.D;

var D = function(selector, attrs) {
    return new D.fn.init(selector, attrs);
};

var init = D.prototype.init = function(selector, attrs) {
    // Nothin
    if (selector === null || selector === undefined) { return this; }

    // Element
    if (selector.nodeType || selector === window) {
        this.push(selector);
        return this;
    }

    // String
    if (isString(selector)) {

        // HTML string
        if (isHtml(selector)) {
            utils.merge(this, parser.parseHtml(selector));
            if (attrs) { this.attr(attrs); }
            return this;
        }

        // Selector: perform a find without creating a new D
        utils.merge(this, selectors.find(selector, true));
        return this;
    }

    // Array of Elements, NodeList, or D object
    if (isArray(selector) || isNodeList(selector) || isD(selector)) {
        utils.merge(this, selector);
        return this;
    }

    // Document a ready
    if (isFunction(selector)) {
        onready(selector);
    }
    return this;
};
init.prototype = D.prototype;

var _hasMoreConflict = false,
    _prevjQuery,
    _prev$;

_.extend(D,
    parser.D,
    data.D,
    deferred.D,
    when.D,
    eventObj.D,
    xaja, // proxy ajax to xaja
{
    each:    array.each,
    forEach: array.each,

    map:     _.map,
    extend:  _.extend,

    noConflict: function() {
        if (_hasMoreConflict) {
            window.jQuery = _prevjQuery;
            window.$ = _prev$;

            _hasMoreConflict = false;
        }

        window.D = _prevD;
        return D;
    },

    moreConflict: function() {
        _hasMoreConflict = true;
        _prevjQuery = window.jQuery;
        _prev$ = window.$;
        window.jQuery = window.Zepto = window.$ = D;
    }
});

var arrayProto = (function(proto, obj) {

    _.each(
        _.splt('length|toString|toLocaleString|join|pop|push|concat|reverse|shift|unshift|slice|splice|sort|some|every|indexOf|lastIndexOf|reduce|reduceRight|map|filter'),
        function(key) {
            obj[key] = proto[key];
        }
    );

    return obj;

}(Array.prototype, {}));

_.extend(
    D.prototype,
    { constructor: D, },
    arrayProto,
    array.fn,
    selectors.fn,
    transversal.fn,
    manip.fn,
    dimensions.fn,
    css.fn,
    attr.fn,
    prop.fn,
    val.fn,
    classes.fn,
    position.fn,
    data.fn,
    events.fn
);

// Expose the prototype so that
// it can be hooked into for plugins
D.fn = D.prototype;

module.exports = D;
<commit_msg>constructor optimization<commit_after>var _ = require('underscore'),

    isArray    = require('is/array'),
    isHtml     = require('is/html'),
    isString   = require('is/string'),
    isNodeList = require('is/nodeList'),
    isFunction = require('is/function'),
    isD        = require('is/d'),

    parser      = require('./modules/parser/parser'),
    utils       = require('./utils'),
    array       = require('./modules/array'),
    onready     = require('./modules/onready'),
    selectors   = require('./modules/selectors'),
    transversal = require('./modules/transversal'),
    dimensions  = require('./modules/dimensions'),
    manip       = require('./modules/manip'),
    css         = require('./modules/css'),
    attr        = require('./modules/attr'),
    prop        = require('./modules/prop'),
    val         = require('./modules/val'),
    position    = require('./modules/position'),
    classes     = require('./modules/classes'),
    data        = require('./modules/data'),
    events      = require('./modules/event/api'),
    eventObj    = require('./modules/event/event'),
    deferred    = require('./modules/Deferred/Deferred'),
    when        = require('./modules/Deferred/when'),

    xaja        = require('xaja-js');

// Store previous reference
var _prevD = window.D;

var D = function(selector, attrs) {
    return new Init(selector, attrs);
};

var Init = D.prototype.init = function(selector, attrs) {
    // nothin
    if (!selector) { return this; }

    // element or window (documents have a nodeType)
    if (selector.nodeType || selector === window) {
        this[0] = selector;
        return this;
    }

    // HTML string
    if (isHtml(selector)) {
        utils.merge(this, parser.parseHtml(selector));
        if (attrs) { this.attr(attrs); }
        return this;
    }

    // String
    if (isString(selector)) {
        // Selector: perform a find without creating a new D
        utils.merge(this, selectors.find(selector, true));
        return this;
    }

    // Array of Elements, NodeList, or D object
    if (isArray(selector) || isNodeList(selector) || isD(selector)) {
        utils.merge(this, selector);
        return this;
    }

    // document ready
    if (isFunction(selector)) {
        onready(selector);
    }
    return this;
};
Init.prototype = D.prototype;

var _hasMoreConflict = false,
    _prevjQuery,
    _prev$;

_.extend(D,
    parser.D,
    data.D,
    deferred.D,
    when.D,
    eventObj.D,
    xaja, // proxy ajax to xaja
{
    each:    array.each,
    forEach: array.each,

    map:     _.map,
    extend:  _.extend,

    noConflict: function() {
        if (_hasMoreConflict) {
            window.jQuery = _prevjQuery;
            window.$ = _prev$;

            _hasMoreConflict = false;
        }

        window.D = _prevD;
        return D;
    },

    moreConflict: function() {
        _hasMoreConflict = true;
        _prevjQuery = window.jQuery;
        _prev$ = window.$;
        window.jQuery = window.Zepto = window.$ = D;
    }
});

var arrayProto = (function(proto, obj) {

    _.each(
        _.splt('length|toString|toLocaleString|join|pop|push|concat|reverse|shift|unshift|slice|splice|sort|some|every|indexOf|lastIndexOf|reduce|reduceRight|map|filter'),
        function(key) {
            obj[key] = proto[key];
        }
    );

    return obj;

}(Array.prototype, {}));

_.extend(
    D.prototype,
    { constructor: D, },
    arrayProto,
    array.fn,
    selectors.fn,
    transversal.fn,
    manip.fn,
    dimensions.fn,
    css.fn,
    attr.fn,
    prop.fn,
    val.fn,
    classes.fn,
    position.fn,
    data.fn,
    events.fn
);

// Expose the prototype so that
// it can be hooked into for plugins
D.fn = D.prototype;

module.exports = D;
<|endoftext|>


<commit_before>var _         = require('underscore'),
    async     = require('async'),
    request   = require('request'),
    qs        = require('querystring'),
    defaults  = require('./defaults'),
    forms     = require('forms'),
    fields    = forms.fields;

/*
TODO

Getting options from multiple functions

Handle MFA
  have testing feature with commandline enter
  User built in funcitions like that ironio one
  Have built in convert to HTML forms
*/

/**
 * Plaid.io node client driver
 *
 * @param  {Object} config
 *   @param  {String} client_id     - Plaid.io "client_id"
 *   @param  {String} secret        - Plaid.io "secret"
 *
 */
var Client = module.exports = function (config) {

  this.initialized = false;

  if (config) {
    this.init(config);
  }
};

/**
 * Initializes this client.
 *
 * @param  {Object} config
 *   @param  {String} client_id     - Plaid.io "client_id"
 *   @param  {String} secret        - Plaid.io "secret"
 *
 */
Client.prototype.init = function (config) {

  if (config.secret.length<0 ||  config.client_id.length<0) {
    throw new Error('plaid-node client must be initialized with a '+
                    'non-empty API "secret" and "client_id" parameter.');
  }

  if (typeof(config.secret)!='string' ||  typeof(config.client_id)!='string') {
    throw new Error('plaid-node client must be initialized with a '+
                    'non-empty API "secret" and "client_id" parameter.');
  }

  this.secret      = config.secret;
  this.client_id   = config.client_id;
  this.config     = _.defaults(config || {}, defaults);

  this.initialized = true;
};

/**
 * Internal method to check whether the client has been initialized.
 * @private
 */
Client.prototype._checkInitialized = function () {
  if (!this.initialized) {
    throw new Error('analytics-node client is not initialized. Please call ' +
                    'client.init(config).');
  }
};

/**
 * Connect a card to the Plaid API
 *
 *
 * @param  {Object} credentials     - The credentials for that card
 *   @param  {String}   username    - id for logged in user
 *   @param  {Password} password    - key/value object of tags for the user (optional)
     ...
 *
 * @param  {Object}  options   - app provided context about the user (optional)
 *
 * @callback {Error, Object, Object}
 *
 */
Client.prototype.connect = function (credentials, type, email, options, callback) {

  this._checkInitialized();

  if (!credentials || typeof(credentials)!= 'object') {
    throw new Error('[plaid]#connect: credentials must be an object');
  }

  if(!callback && (typeof options ==='function')) {
    callback = options;
    options  = {};
  }

  if(!type || typeof(type)!='string'){
    throw new Error('[plaid]#connect: Type missing or invalid');
  }

  if(!email || typeof(email)!='string'){
    throw new Error('[plaid]#connect: Email missing or invalid');
  }

  if(!callback){
    callback = function(){};
  }

  this.options     = options;
  this.credentials = credentials;
  this.type        = type;
  this.email       = email;

  // No access token or mfa for a connect.
  if (this.access_token) {
    this.access_token = null;
  }
  if (this.mfa) {
    this.mfa = null;
  }

  return this._exec('submit', callback);
};

Client.prototype.step = function (access_token, mfa, options, callback) {

  this._checkInitialized();

  if(!callback && typeof(options)=='function'){
    callback = options;
    options  = {};
  }

  if(!callback){
    callback = function(){};
  }

  this.options      = options;
  this.access_token = access_token;
  this.mfa          = mfa;

  return this._exec('step', callback);
};

Client.prototype.get = function(access_token, options, callback) {
  this._checkInitialized();

  if(!callback && typeof(options) == 'function') {
    callback = options;
    options = {};
  }

  this.options = options;

  this.access_token = access_token;

  return this._exec('get', callback);
};

Client.prototype.remove = function(access_token, options, callback) {
  this._checkInitialized();

  if(!callback && typeof(options) == 'function') {
    callback = options;
    options = {};
  }

  this.options = options;

  this.access_token = access_token;

  return this._exec('remove', callback);
};

Client.prototype._exec = function (method, callback){

  var uri = this.config.protocol + this.config.host + '/' + this.config.endpoint[method].route;

  var query = {
    client_id   : this.client_id,
    secret      : this.secret,
    credentials : JSON.stringify(this.credentials),
    type        : this.type,
    email       : this.email,
    access_token: this.access_token,
    options     : JSON.stringify(this.options),
    mfa         : this.mfa
  };

  // the login option has to be set a separate parameter
  if (this.options.login) {
    query.login = this.options.login;
  }

  uri += "?"+qs.stringify(query);

  var self = this;

  request(
    { method: this.config.endpoint[method].method,
      uri: uri
    //, qs : qs.stringify(query)
    },
    function (error, response, body) {
      if(!response) {
        response = {};
      }
      if(error || ( response.statusCode > 299 ) ) {
        return self._handleError(error, response.statusCode, body, callback);
      }

      self.body = body;
      return self._handleSuccess(callback);

    }
  );
};

Client.prototype._handleSuccess = function(callback){
  try{
    this.body = JSON.parse(this.body);
  }catch(err){
    return callback("Couldn't parse body");
  }

  if(this.body.status === 'MFA') {
    return this._handleMFA(callback);
  }

  return callback(null, this.body, (typeof this.body.mfa !== 'undefined'));
};

Client.prototype._handleError = function(error, status, body, callback){
  if(error) {
    return callback(error);
  }

  try{
    body = JSON.parse(body);
  }catch(err){
    return callback("Couldn't parse body");
  }

  return callback(body);
};

Client.prototype._handleMFA = function(callback){

  this.config.endpoint  = '/connect/submit/step';
  this.access_token     = this.access_token   || this.body.accessToken;
  this.options.itemID   = this.options.itemID || this.body.message.itemID;

  var self = this;
  //helper
  var step = function(credentials, callback){
    if(self.options.mfaCL) {
      return self._mfaCL(credentials, callback);
    }
    return self.connect(credentials, self.type, self.email, self.options, callback);
  };
  var html = function(){
    return self._formToHTML(self.body.message.form);
  };

  this.body.message.step = step;
  if(this.body.message.form) {
    this.body.message.form.html = html;
  } else {
    console.log(this.body.message);
  }

  return callback(null, this.body, true);
};

/* MFA testing CL */

Client.prototype._mfaCL = function(credentials, callback){
  var readline = require('readline');
  var credentials = {};

  //Making sure there is a valid form object
  var holder;
  if(this.body.message.form) {
    holder = this.body.message.form;
  }
  else{
    return console.log("Unknown message");
  }

  var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });

  //The function that is called for every question
  var read = function(question, cbk){
    var display = question.display + ": ";
    rl.question(display, function(answer) {
      credentials[display]=answer;
      return cbk();
    });
  };

  var self = this;
  async.forEachSeries(holder, read, function(){

    //Closing the readline interface
    rl.close();
    self.credentials = credentials;

    return self.connect(self.credentials, self.type, self.email, self.options, callback);
  });
};

Client.prototype._formToHTML = function(raw){
  var form = {};

  for(i in raw){
    if(raw[i].type=='text') {
      form[raw[i].display]=fields.string();
    }
  }

  var form = forms.create(form).toHTML();

  return '<form>'+form+'</form>';

};
<commit_msg>lint: remove superfluous variable declarations<commit_after>var _         = require('underscore'),
    async     = require('async'),
    request   = require('request'),
    qs        = require('querystring'),
    defaults  = require('./defaults'),
    forms     = require('forms'),
    fields    = forms.fields;

/*
TODO

Getting options from multiple functions

Handle MFA
  have testing feature with commandline enter
  User built in funcitions like that ironio one
  Have built in convert to HTML forms
*/

/**
 * Plaid.io node client driver
 *
 * @param  {Object} config
 *   @param  {String} client_id     - Plaid.io "client_id"
 *   @param  {String} secret        - Plaid.io "secret"
 *
 */
var Client = module.exports = function (config) {

  this.initialized = false;

  if (config) {
    this.init(config);
  }
};

/**
 * Initializes this client.
 *
 * @param  {Object} config
 *   @param  {String} client_id     - Plaid.io "client_id"
 *   @param  {String} secret        - Plaid.io "secret"
 *
 */
Client.prototype.init = function (config) {

  if (config.secret.length<0 ||  config.client_id.length<0) {
    throw new Error('plaid-node client must be initialized with a '+
                    'non-empty API "secret" and "client_id" parameter.');
  }

  if (typeof(config.secret)!='string' ||  typeof(config.client_id)!='string') {
    throw new Error('plaid-node client must be initialized with a '+
                    'non-empty API "secret" and "client_id" parameter.');
  }

  this.secret      = config.secret;
  this.client_id   = config.client_id;
  this.config     = _.defaults(config || {}, defaults);

  this.initialized = true;
};

/**
 * Internal method to check whether the client has been initialized.
 * @private
 */
Client.prototype._checkInitialized = function () {
  if (!this.initialized) {
    throw new Error('analytics-node client is not initialized. Please call ' +
                    'client.init(config).');
  }
};

/**
 * Connect a card to the Plaid API
 *
 *
 * @param  {Object} credentials     - The credentials for that card
 *   @param  {String}   username    - id for logged in user
 *   @param  {Password} password    - key/value object of tags for the user (optional)
     ...
 *
 * @param  {Object}  options   - app provided context about the user (optional)
 *
 * @callback {Error, Object, Object}
 *
 */
Client.prototype.connect = function (credentials, type, email, options, callback) {

  this._checkInitialized();

  if (!credentials || typeof(credentials)!= 'object') {
    throw new Error('[plaid]#connect: credentials must be an object');
  }

  if(!callback && (typeof options ==='function')) {
    callback = options;
    options  = {};
  }

  if(!type || typeof(type)!='string'){
    throw new Error('[plaid]#connect: Type missing or invalid');
  }

  if(!email || typeof(email)!='string'){
    throw new Error('[plaid]#connect: Email missing or invalid');
  }

  if(!callback){
    callback = function(){};
  }

  this.options     = options;
  this.credentials = credentials;
  this.type        = type;
  this.email       = email;

  // No access token or mfa for a connect.
  if (this.access_token) {
    this.access_token = null;
  }
  if (this.mfa) {
    this.mfa = null;
  }

  return this._exec('submit', callback);
};

Client.prototype.step = function (access_token, mfa, options, callback) {

  this._checkInitialized();

  if(!callback && typeof(options)=='function'){
    callback = options;
    options  = {};
  }

  if(!callback){
    callback = function(){};
  }

  this.options      = options;
  this.access_token = access_token;
  this.mfa          = mfa;

  return this._exec('step', callback);
};

Client.prototype.get = function(access_token, options, callback) {
  this._checkInitialized();

  if(!callback && typeof(options) == 'function') {
    callback = options;
    options = {};
  }

  this.options = options;

  this.access_token = access_token;

  return this._exec('get', callback);
};

Client.prototype.remove = function(access_token, options, callback) {
  this._checkInitialized();

  if(!callback && typeof(options) == 'function') {
    callback = options;
    options = {};
  }

  this.options = options;

  this.access_token = access_token;

  return this._exec('remove', callback);
};

Client.prototype._exec = function (method, callback){

  var uri = this.config.protocol + this.config.host + '/' + this.config.endpoint[method].route;

  var query = {
    client_id   : this.client_id,
    secret      : this.secret,
    credentials : JSON.stringify(this.credentials),
    type        : this.type,
    email       : this.email,
    access_token: this.access_token,
    options     : JSON.stringify(this.options),
    mfa         : this.mfa
  };

  // the login option has to be set a separate parameter
  if (this.options.login) {
    query.login = this.options.login;
  }

  uri += "?"+qs.stringify(query);

  var self = this;

  request(
    { method: this.config.endpoint[method].method,
      uri: uri
    //, qs : qs.stringify(query)
    },
    function (error, response, body) {
      if(!response) {
        response = {};
      }
      if(error || ( response.statusCode > 299 ) ) {
        return self._handleError(error, response.statusCode, body, callback);
      }

      self.body = body;
      return self._handleSuccess(callback);

    }
  );
};

Client.prototype._handleSuccess = function(callback){
  try{
    this.body = JSON.parse(this.body);
  }catch(err){
    return callback("Couldn't parse body");
  }

  if(this.body.status === 'MFA') {
    return this._handleMFA(callback);
  }

  return callback(null, this.body, (typeof this.body.mfa !== 'undefined'));
};

Client.prototype._handleError = function(error, status, body, callback){
  if(error) {
    return callback(error);
  }

  try{
    body = JSON.parse(body);
  }catch(err){
    return callback("Couldn't parse body");
  }

  return callback(body);
};

Client.prototype._handleMFA = function(callback){

  this.config.endpoint  = '/connect/submit/step';
  this.access_token     = this.access_token   || this.body.accessToken;
  this.options.itemID   = this.options.itemID || this.body.message.itemID;

  var self = this;
  //helper
  var step = function(credentials, callback){
    if(self.options.mfaCL) {
      return self._mfaCL(credentials, callback);
    }
    return self.connect(credentials, self.type, self.email, self.options, callback);
  };
  var html = function(){
    return self._formToHTML(self.body.message.form);
  };

  this.body.message.step = step;
  if(this.body.message.form) {
    this.body.message.form.html = html;
  } else {
    console.log(this.body.message);
  }

  return callback(null, this.body, true);
};

/* MFA testing CL */

Client.prototype._mfaCL = function(credentials, callback){
  var readline = require('readline');
  credentials = {};

  //Making sure there is a valid form object
  var holder;
  if(this.body.message.form) {
    holder = this.body.message.form;
  }
  else{
    return console.log("Unknown message");
  }

  var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });

  //The function that is called for every question
  var read = function(question, cbk){
    var display = question.display + ": ";
    rl.question(display, function(answer) {
      credentials[display]=answer;
      return cbk();
    });
  };

  var self = this;
  async.forEachSeries(holder, read, function(){

    //Closing the readline interface
    rl.close();
    self.credentials = credentials;

    return self.connect(self.credentials, self.type, self.email, self.options, callback);
  });
};

Client.prototype._formToHTML = function(raw){
  var form = {};

  for(i in raw){
    if(raw[i].type=='text') {
      form[raw[i].display]=fields.string();
    }
  }

  form = forms.create(form).toHTML();

  return '<form>'+form+'</form>';

};
<|endoftext|>


<commit_before>import Http from './http';
import Form from './form';
import FormErrors from './form-errors';

function Plugin (Vue) {

    Object.defineProperty(Vue, '$form', {

        /*
         * Create a new Form instance.
         */
        create(fields) {
            return new Form(fields);
        },

        /*
         * Create a new FormErrors instance.
         */
        errors() {
            return new FormErrors();
        },

        /*
         * Submit the given Form to the given URI via a DELETE request.
         */
        delete(uri, form) {
            return Http.deleteForm(uri, form);
        },

        /*
         * Submit the given Form to the given URI via a POST request.
         */
        post(uri, form) {
            return Http.postForm(uri, form);
        },

        /*
         * Submit the given Form to the given URI via a PUT request
         */
        put(uri, form) {
            return Http.putForm(uri, form);
        },

        /*
         * Submit the given Form to the given URI using the given HTTP method.
         */
        submit(method, uri, form, formData = null) {
            return Http.sendForm(method, uri, form, formData);
        }

    });
}

if (typeof window !== 'undefined' && window.Vue) {
    window.Vue.use(Plugin);
}

export { Plugin, Http, Form, FormErrors }
<commit_msg>rename vue plugin function<commit_after>import Http from './http';
import Form from './form';
import FormErrors from './form-errors';

function FormHelpers (Vue) {

    Object.defineProperty(Vue, '$form', {

        /*
         * Create a new Form instance.
         */
        create(fields) {
            return new Form(fields);
        },

        /*
         * Create a new FormErrors instance.
         */
        errors() {
            return new FormErrors();
        },

        /*
         * Submit the given Form to the given URI via a DELETE request.
         */
        delete(uri, form) {
            return Http.deleteForm(uri, form);
        },

        /*
         * Submit the given Form to the given URI via a POST request.
         */
        post(uri, form) {
            return Http.postForm(uri, form);
        },

        /*
         * Submit the given Form to the given URI via a PUT request
         */
        put(uri, form) {
            return Http.putForm(uri, form);
        },

        /*
         * Submit the given Form to the given URI using the given HTTP method.
         */
        submit(method, uri, form, formData = null) {
            return Http.sendForm(method, uri, form, formData);
        }

    });
}

if (typeof window !== 'undefined' && window.Vue) {
    window.Vue.use(FormHelpers);
}

export { FormHelpers, Http, Form, FormErrors }
<|endoftext|>


<commit_before>import React, { Component } from "react";
import { render } from "react-dom";
import App from "./App";
import "bootstrap/dist/css/bootstrap.min.css";
import "./styles/index.css";

class About extends Component {
  render() {
    return (
      <div>
        aaaaaaaaaaa
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));
<commit_msg>Forgot to DELET THIS<commit_after>import React, { Component } from "react";
import { render } from "react-dom";
import App from "./App";
import "bootstrap/dist/css/bootstrap.min.css";
import "./styles/index.css";

render(<App />, document.getElementById("root"));
<|endoftext|>


<commit_before>/*jslint node: true, nomen: true, es5: true */
/**
 * Developed By Carlo Bernaschina (GitHub - B3rn475)
 * www.bernaschina.com
 *
 * Distributed under the MIT Licence
 */
"use strict";

var ipaddr = require('ipaddr.js');

module.exports = function (socket, address) {
	// @TODO check inputs
	var addr = ipaddr.parse(address),
		buffer;
	switch (addr.kind()) {
	case "ipv4":
		(function () {
			var i = 1;
			buffer = new Buffer(5);
			buffer.writeUInt8(4,0);
			addr.toByteArray().forEach(function (octet) {
				buffer.writeUInt8(octet, i);
				i = i + 1;
			});
		}());
		break;
	case "ipv6":
		(function () {
			var i = 1;
			buffer = new Buffer(17);
			buffer.writeUInt8(16,0);
			addr.toByteArray().forEach(function (octet) {
				buffer.writeUInt8(octet, i);
				i = i + 1;
			});
		}());
		break;
	}
	socket.write(buffer);
	return socket;
}<commit_msg>Fixed Missing IP type field<commit_after>/*jslint node: true, nomen: true, es5: true */
/**
 * Developed By Carlo Bernaschina (GitHub - B3rn475)
 * www.bernaschina.com
 *
 * Distributed under the MIT Licence
 */
"use strict";

var ipaddr = require('ipaddr.js');

module.exports = function (socket, address) {
	// @TODO check inputs
	var addr = ipaddr.parse(address),
		buffer;
	switch (addr.kind()) {
	case "ipv4":
		(function () {
			var i = 2;
			buffer = new Buffer(6);
			buffer.writeUInt8(5, 0);
            buffer.writeUInt8(0, 1);
			addr.toByteArray().forEach(function (octet) {
				buffer.writeUInt8(octet, i);
				i = i + 1;
			});
		}());
		break;
	case "ipv6":
		(function () {
			var i = 2;
			buffer = new Buffer(18);
			buffer.writeUInt8(17, 0);
            buffer.writeUInt8(1, 1);
			addr.toByteArray().forEach(function (octet) {
				buffer.writeUInt8(octet, i);
				i = i + 1;
			});
		}());
		break;
	}
	socket.write(buffer);
	return socket;
};<|endoftext|>


<commit_before>'use strict';

let fs = require('fs'),
    path = require('path');

class PugThemer {

  /**
   * Initializes an new instance of PugThemer and returns the middleware function.
   */
  static init() {
    let themer = new PugThemer();
    return function(req, res, next) {
      themer.onTheme(req, res);
      next();
    };
  }

  /**
   * The REAL middleware function, setups of the Pug lexer, the response functions and calls the theme render.
   *
   * @param {Express.Request} req The Express.Request object
   * @param {Express.Response} res The Express.Response object
   */
  onTheme(req, res) {
    /**
     * This sets up the pug lexer and allows us to go through it before
     * the paths get used.
     */
    res.locals.plugins = [{
      postLex: function(value, options) {
        PugThemer.postPugLexer(res, value, options);
        return value;
      }
    }];

    /**
     * Sets up the theme function on the response objection.
     * If a parameter is passed - set the theme only for this response.
     * Otherwise attempt to get the theme based on the following priority:
     * response.theme
     * app.locals.theme - app global
     * app.get('theme') - app global (two different ways to set, one needs priority)
     * finally use the "default" theme
     */
    res.theme = function(theme) {
      if (arguments.length) {
        this._theme = theme;
        return this;
      }
      return this._theme || req.app.locals.theme || req.app.get('theme') || 'default';
    }.bind(res);

    let vw = req.app.get('view');

    //console.log('Req: ', typeof vw, vw.prototype.render);
    if (!PugThemer._viewLookup) {
      PugThemer._viewLookup = vw.prototype.lookup;
      vw.prototype.lookup = function(name) {
        return name;
      };
    }
    if (!PugThemer._viewRender) {
      PugThemer._viewRender = vw.prototype.render;
      vw.prototype.render = function(options, callback) {
        let p = options['express-theme-pug.realpath'];
        let checkFile = path.join(path.dirname(p), PugThemer.appendExt(null, path.basename(p), this.ext));
        let realFile = PugThemer._viewLookup.call(this, checkFile);
        delete options['express-theme-pug.realpath'];
        this.engine(realFile, options, callback);
      };
    }

    /**
     * Replace the default render function so it is theme aware.
     */
    let _render = res.render;
    res.render = function(view, renderOptions, fn) {
      let options = renderOptions;
      let callback = fn;

      if (typeof renderOptions === 'function') {
        callback = renderOptions;
        options = {};
      }
      if (typeof options === 'undefined') {
        options = {};
      }

      let themePrefix = PugThemer.getThemePrefix(this, view);
      if (themePrefix === '') {
        let dirs = Array.isArray(PugThemer.baseViews) && PugThemer.baseViews.length > 1 ?
            'directories "' + PugThemer.baseViews.slice(0, -1).join('", "') + '" or "' + PugThemer.baseViews[PugThemer.baseViews.length - 1] + '"' :
            'directory "' + PugThemer.baseViews + '"';
        throw new Error('Failed to lookup view "' + view + '" in views ' + dirs);
      }

      options['express-theme-pug.realpath'] = path.join(themePrefix, view);
      return _render.call(this, path.join(this.theme(), view), options, callback);
    };
  }

  /**
   * Processes the Pug lexer tokens for paths and updates them for the theme.
   *
   * @param {Express.Response} res The Express Response object.
   * @param {Array} tokens Tokens returned by the pug lexer.
   * @param {Object} options Lexer options.
   */
  static postPugLexer(res, tokens, options) {
    let views = PugThemer.getThemeViews(res);

    let currentTheme = null;
    for (const view of views) {
      let relative = path.relative(view.path, options.filename);
      if (relative[0] !== '.') {
        currentTheme = view;
        currentTheme.relativeToFile = relative;
        break;
      }
    }

    for (let token of tokens) {
      if (token.type === 'path') {
        for (const view of views) {
          let originalTarget = path.join(path.dirname(options.filename), token.val);
          originalTarget = PugThemer.appendExt(res, originalTarget);

          let relativeToCurrentView = path.relative(currentTheme.path, originalTarget);

          let viewPath = path.join(view.path, relativeToCurrentView);
          let filePath = path.resolve(viewPath);

          if (fs.existsSync(filePath)) {
            token.val = path.relative(path.dirname(options.filename), filePath);
            break;
          }
        } // for:views
      } // if:token.type
    } // for:token
  }

  /**
   * Gets an array of the theme views and caches theme as they are generated.
   *
   * @param {Express.Response} res The Express Response object.
   */
  static getThemeViews(res) {
    if (!PugThemer.baseViews) {
      PugThemer.baseViews = res.app.get('views');
      if (!Array.isArray(PugThemer.baseViews)) PugThemer.baseViews = [PugThemer.baseViews];
    }

    if (!PugThemer.views) PugThemer.views = {};

    let reqTheme = res.theme();
    let defaultTheme = res.app.locals.theme || res.app.get('theme') || 'default';
    if (reqTheme === defaultTheme && defaultTheme !== 'default')
      defaultTheme = 'default';
    let themeKey = reqTheme+'.'+defaultTheme;
    let themes = [reqTheme, defaultTheme, 'default'].filter(function(x,i,a){ return i === a.indexOf(x); });

    if (!PugThemer.views[themeKey]) {
      let views = [];
      for(const view of PugThemer.baseViews) {
        for(const theme of themes) {
          views.push({theme: theme, path: path.join(view, theme), base: view});
        }
      }
      PugThemer.views[themeKey] = views;
    }
    return PugThemer.views[themeKey];
  }

  /**
   * Gets the theme for the specified file.
   *
   * Note: Does not return the full path, just the prefix needed before the specified viewFile.
   *
   * @param {Express.Response} res The Express Response object.
   * @param {String} viewFile The view file being accessed.
   */
  static getThemePrefix(res, viewFile) {
    let views = PugThemer.getThemeViews(res);
    viewFile = PugThemer.appendExt(res, viewFile);

    let viewFound = false;
    for(const view of views) {
      let viewPath = path.join(view.path, viewFile);
      if (fs.existsSync(viewPath)) {
        viewFound = view.theme;
        break;
      }
    }
    return viewFound ? viewFound : '';
  }

  static appendExt(res, file, ext) {
    let fileExt = path.extname(file);
    if (fileExt === '') {
      if (!ext) {
        ext = res.app.get('view engine');
        ext = ext[0] !== '.' ? '.' + ext : ext;
      }
      return file + ext;
    }
    return file;
  }
}

module.exports = PugThemer.init();<commit_msg>did some cleanup functions no longer get created with EVERY request - now the prototypes are getting updated<commit_after>'use strict';

let fs = require('fs'),
    path = require('path');

class PugThemer {

  /**
   * Initializes an new instance of PugThemer and returns the middleware function.
   */
  static init() {
    let themer = new PugThemer();
    return function(req, res, next) {
      themer.onTheme(req, res);
      next();
    };
  }

  /**
   * The REAL middleware function, setups of the Pug lexer, the response functions and calls the theme render.
   *
   * @param {Express.Request} req The Express.Request object
   * @param {Express.Response} res The Express.Response object
   */
  onTheme(req, res) {
    /**
     * This sets up the pug lexer and allows us to go through it before
     * the paths get used.
     */
    res.locals.plugins = [{
      postLex: function(value, options) {
        PugThemer.postPugLexer(res, value, options);
        return value;
      }
    }];

    /**
     * Sets up the theme function on the response objection.
     * If a parameter is passed - set the theme only for this response.
     * Otherwise attempt to get the theme based on the following priority:
     * response.theme
     * app.locals.theme - app global
     * app.get('theme') - app global (two different ways to set, one needs priority)
     * finally use the "default" theme
     */
    if (!req.app.response.theme) {
      req.app.response.theme = function(theme) {
        if (arguments.length) {
          this._theme = theme;
          return this;
        }
        return this._theme || req.app.locals.theme || req.app.get('theme') || 'default';
      };
    }

    let vw = req.app.get('view');

    if (!PugThemer._viewLookup) {
      PugThemer._viewLookup = vw.prototype.lookup;
      vw.prototype.lookup = function(name) {
        return name;
      };
    }
    if (!PugThemer._viewRender) {
      PugThemer._viewRender = vw.prototype.render;
      vw.prototype.render = function(options, callback) {
        let p = options['express-theme-pug.realpath'];
        let checkFile = path.join(path.dirname(p), PugThemer.appendExt(null, path.basename(p), this.ext));
        let realFile = PugThemer._viewLookup.call(this, checkFile);
        delete options['express-theme-pug.realpath'];
        this.engine(realFile, options, callback);
      };
    }

    /**
     * Replace the default render function so it is theme aware.
     */
    if (!PugThemer._responseRender) {
      PugThemer._responseRender = req.app.response.render;
      req.app.response.render = function(view, renderOptions, fn) {
        let options = renderOptions;
        let callback = fn;

        if (typeof renderOptions === 'function') {
          callback = renderOptions;
          options = {};
        }
        if (typeof options === 'undefined') {
          options = {};
        }

        let themePrefix = PugThemer.getThemePrefix(this, view);
        if (themePrefix === '') {
          let dirs = Array.isArray(PugThemer.baseViews) && PugThemer.baseViews.length > 1 ?
              'directories "' + PugThemer.baseViews.slice(0, -1).join('", "') + '" or "' + PugThemer.baseViews[PugThemer.baseViews.length - 1] + '"' :
              'directory "' + PugThemer.baseViews + '"';
          throw new Error('Failed to lookup view "' + view + '" in views ' + dirs);
        }

        options['express-theme-pug.realpath'] = path.join(themePrefix, view);
        return PugThemer._responseRender.call(this, path.join(this.theme(), view), options, callback);
      };
    }
  }

  /**
   * Processes the Pug lexer tokens for paths and updates them for the theme.
   *
   * @param {Express.Response} res The Express Response object.
   * @param {Array} tokens Tokens returned by the pug lexer.
   * @param {Object} options Lexer options.
   */
  static postPugLexer(res, tokens, options) {
    let views = PugThemer.getThemeViews(res);

    let currentTheme = null;
    for (const view of views) {
      let relative = path.relative(view.path, options.filename);
      if (relative[0] !== '.') {
        currentTheme = view;
        currentTheme.relativeToFile = relative;
        break;
      }
    }

    for (let token of tokens) {
      if (token.type === 'path') {
        for (const view of views) {
          let originalTarget = path.join(path.dirname(options.filename), token.val);
          originalTarget = PugThemer.appendExt(res, originalTarget);

          let relativeToCurrentView = path.relative(currentTheme.path, originalTarget);

          let viewPath = path.join(view.path, relativeToCurrentView);
          let filePath = path.resolve(viewPath);

          if (fs.existsSync(filePath)) {
            token.val = path.relative(path.dirname(options.filename), filePath);
            break;
          }
        } // for:views
      } // if:token.type
    } // for:token
  }

  /**
   * Gets an array of the theme views and caches theme as they are generated.
   *
   * @param {Express.Response} res The Express Response object.
   */
  static getThemeViews(res) {
    if (!PugThemer.baseViews) {
      PugThemer.baseViews = res.app.get('views');
      if (!Array.isArray(PugThemer.baseViews)) PugThemer.baseViews = [PugThemer.baseViews];
    }

    if (!PugThemer.views) PugThemer.views = {};

    let reqTheme = res.theme();
    let defaultTheme = res.app.locals.theme || res.app.get('theme') || 'default';
    if (reqTheme === defaultTheme && defaultTheme !== 'default')
      defaultTheme = 'default';
    let themeKey = reqTheme+'.'+defaultTheme;
    let themes = [reqTheme, defaultTheme, 'default'].filter(function(x,i,a){ return i === a.indexOf(x); });

    if (!PugThemer.views[themeKey]) {
      let views = [];
      for(const view of PugThemer.baseViews) {
        for(const theme of themes) {
          views.push({theme: theme, path: path.join(view, theme), base: view});
        }
      }
      PugThemer.views[themeKey] = views;
    }
    return PugThemer.views[themeKey];
  }

  /**
   * Gets the theme for the specified file.
   *
   * Note: Does not return the full path, just the prefix needed before the specified viewFile.
   *
   * @param {Express.Response} res The Express Response object.
   * @param {String} viewFile The view file being accessed.
   */
  static getThemePrefix(res, viewFile) {
    let views = PugThemer.getThemeViews(res);
    viewFile = PugThemer.appendExt(res, viewFile);

    let viewFound = false;
    for(const view of views) {
      let viewPath = path.join(view.path, viewFile);
      if (fs.existsSync(viewPath)) {
        viewFound = view.theme;
        break;
      }
    }
    return viewFound ? viewFound : '';
  }

  static appendExt(res, file, ext) {
    let fileExt = path.extname(file);
    if (fileExt === '') {
      if (!ext) {
        ext = res.app.get('view engine');
        ext = ext[0] !== '.' ? '.' + ext : ext;
      }
      return file + ext;
    }
    return file;
  }
}

module.exports = PugThemer.init();<|endoftext|>


<commit_before>require('Common');
var win = new Window();
application.exitAfterWindowsClose = true;
win.visible = true;
win.title = "Hi Tint World!";

var webview = new WebView(); // Create a new webview for HTML.
win.appendChild(webview); // attach the webview to the window.

// position the webview 0 pixels from all the window's edges.
webview.left=webview.right=webview.top=webview.bottom=0;

// What we should do when the web-page loads.
webview.addEventListener('load', function() {
    webview.postMessage(JSON.stringify(process.versions));
});

webview.location = "app://src/index.html"; // Tell the webview to render the index.html<commit_msg>Add toolbar with back button<commit_after>require('Common');
var win = new Window();
var toolbar = new Toolbar();

application.exitAfterWindowsClose = true;
win.visible = true;
win.title = "Hi Tint World!";

btn = new Button();
btn.image = 'back';
toolbar.appendChild( btn );
win.toolbar = toolbar;

var webview = new WebView(); // Create a new webview for HTML.
win.appendChild(webview); // attach the webview to the window.

// position the webview 0 pixels from all the window's edges.
webview.left=webview.right=webview.top=webview.bottom=0;

// What we should do when the web-page loads.
webview.addEventListener('load', function() {
    webview.postMessage(JSON.stringify(process.versions));
});

webview.location = "app://src/index.html"; // Tell the webview to render the index.html<|endoftext|>


<commit_before>//@flow
import React, { Component } from "react";
import { View, NativeModules, Platform, findNodeHandle } from "react-native";
const { RNViewShot } = NativeModules;

const neverEndingPromise = new Promise(() => {});

type Options = {
  width?: number,
  height?: number,
  format: "png" | "jpg" | "webm",
  quality: number,
  result: "tmpfile" | "base64" | "data-uri",
  snapshotContentContainer: boolean
};

if (!RNViewShot) {
  console.warn(
    "NativeModules.RNViewShot is undefined. Make sure the library is linked on the native side."
  );
}

const acceptedFormats = ["png", "jpg"].concat(
  Platform.OS === "android" ? ["webm"] : []
);

const acceptedResults = ["tmpfile", "base64", "data-uri"];

const defaultOptions = {
  format: "png",
  quality: 1,
  result: "tmpfile",
  snapshotContentContainer: false
};

// validate and coerce options
function validateOptions(
  options: ?Object
): { options: Options, errors: Array<string> } {
  options = {
    ...defaultOptions,
    ...options
  };
  const errors = [];
  if (
    "width" in options &&
    (typeof options.width !== "number" || options.width <= 0)
  ) {
    errors.push("option width should be a positive number");
    delete options.width;
  }
  if (
    "height" in options &&
    (typeof options.height !== "number" || options.height <= 0)
  ) {
    errors.push("option height should be a positive number");
    delete options.height;
  }
  if (
    typeof options.quality !== "number" ||
    options.quality < 0 ||
    options.quality > 1
  ) {
    errors.push("option quality should be a number between 0.0 and 1.0");
    options.quality = defaultOptions.quality;
  }
  if (typeof options.snapshotContentContainer !== "boolean") {
    errors.push("option snapshotContentContainer should be a boolean");
  }
  if (acceptedFormats.indexOf(options.format) === -1) {
    options.format = defaultOptions.format;
    errors.push(
      "option format is not in valid formats: " + acceptedFormats.join(" | ")
    );
  }
  if (acceptedResults.indexOf(options.result) === -1) {
    options.result = defaultOptions.result;
    errors.push(
      "option result is not in valid formats: " + acceptedResults.join(" | ")
    );
  }
  return { options, errors };
}

export function captureRef(
  view: number | ReactElement<*>,
  optionsObject?: Object
): Promise<string> {
  if (typeof view !== "number") {
    const node = findNodeHandle(view);
    if (!node)
      return Promise.reject(
        new Error("findNodeHandle failed to resolve view=" + String(view))
      );
    view = node;
  }
  const { options, errors } = validateOptions(optionsObject);
  if (__DEV__ && errors.length > 0) {
    console.warn(
      "react-native-view-shot: bad options:\n" +
        errors.map(e => `- ${e}`).join("\n")
    );
  }
  return RNViewShot.captureRef(view, options);
}

export function releaseCapture(uri: string): void {
  if (typeof uri !== "string") {
    if (__DEV__) {
      console.warn("Invalid argument to releaseCapture. Got: " + uri);
    }
  } else {
    RNViewShot.releaseCapture(uri);
  }
}

export function captureScreen(
  optionsObject?: Options
): Promise<string> {
  const { options, errors } = validateOptions(optionsObject);
  if (__DEV__ && errors.length > 0) {
    console.warn(
      "react-native-view-shot: bad options:\n" +
        errors.map(e => `- ${e}`).join("\n")
    );
  }
  return RNViewShot.captureScreen(options);
}

type Props = {
  options?: Object,
  captureMode?: "mount" | "continuous" | "update",
  children: React.Element<*>,
  onLayout?: (e: *) => void,
  onCapture: (uri: string) => void,
  onCaptureFailure: (e: Error) => void
};

function checkCompatibleProps(props: Props) {
  if (!props.captureMode && props.onCapture) {
    console.warn(
      "react-native-view-shot: a captureMode prop must be provided for `onCapture`"
    );
  } else if (props.captureMode && !props.onCapture) {
    console.warn(
      "react-native-view-shot: captureMode prop is defined but onCapture prop callback is missing"
    );
  } else if (
    (props.captureMode === "continuous" || props.captureMode === "update") &&
    props.options &&
    props.options.result &&
    props.options.result !== "tmpfile"
  ) {
    console.warn(
      "react-native-view-shot: result=tmpfile is recommended for captureMode=" +
        props.captureMode
    );
  }
}

export default class ViewShot extends Component {
  static captureRef = captureRef;
  static releaseCapture = releaseCapture;
  props: Props;
  root: ?View;

  _raf: *;
  lastCapturedURI: ?string;

  resolveFirstLayout: (layout: Object) => void;
  firstLayoutPromise = new Promise(resolve => {
    this.resolveFirstLayout = resolve;
  });

  capture = (): Promise<string> =>
    this.firstLayoutPromise
      .then(() => {
        const { root } = this;
        if (!root) return neverEndingPromise; // component is unmounted, you never want to hear back from the promise
        return captureRef(root, this.props.options);
      })
      .then(
        (uri: string) => {
          this.onCapture(uri);
          return uri;
        },
        (e: Error) => {
          this.onCaptureFailure(e);
          throw e;
        }
      );

  onCapture = (uri: string) => {
    if (!this.root) return;
    if (this.lastCapturedURI) {
      // schedule releasing the previous capture
      setTimeout(releaseCapture, 500, this.lastCapturedURI);
    }
    this.lastCapturedURI = uri;
    const { onCapture } = this.props;
    if (onCapture) onCapture(uri);
  };

  onCaptureFailure = (e: Error) => {
    if (!this.root) return;
    const { onCaptureFailure } = this.props;
    if (onCaptureFailure) onCaptureFailure(e);
  };

  syncCaptureLoop = (captureMode: ?string) => {
    cancelAnimationFrame(this._raf);
    if (captureMode === "continuous") {
      let previousCaptureURI = "-"; // needs to capture at least once at first, so we use "-" arbitrary string
      const loop = () => {
        this._raf = requestAnimationFrame(loop);
        if (previousCaptureURI === this.lastCapturedURI) return; // previous capture has not finished, don't capture yet
        previousCaptureURI = this.lastCapturedURI;
        this.capture();
      };
      this._raf = requestAnimationFrame(loop);
    }
  };

  onRef = (ref: View) => {
    this.root = ref;
  };

  onLayout = (e: { nativeEvent: { layout: Object } }) => {
    const { onLayout } = this.props;
    this.resolveFirstLayout(e.nativeEvent.layout);
    if (onLayout) onLayout(e);
  };

  componentDidMount() {
    if (__DEV__) checkCompatibleProps(this.props);
    if (this.props.captureMode === "mount") {
      this.capture();
    } else {
      this.syncCaptureLoop(this.props.captureMode);
    }
  }

  componentWillReceiveProps(nextProps: Props) {
    if (nextProps.captureMode !== this.props.captureMode) {
      this.syncCaptureLoop(nextProps.captureMode);
    }
  }

  componentDidUpdate() {
    if (this.props.captureMode === "update") {
      this.capture();
    }
  }

  componentWillUnmount() {
    this.syncCaptureLoop(null);
  }

  render() {
    const { children } = this.props;
    return (
      <View ref={this.onRef} collapsable={false} onLayout={this.onLayout}>
        {children}
      </View>
    );
  }
}
<commit_msg>make onCapture & onCaptureFailure props optional in flow type<commit_after>//@flow
import React, { Component } from "react";
import { View, NativeModules, Platform, findNodeHandle } from "react-native";
const { RNViewShot } = NativeModules;

const neverEndingPromise = new Promise(() => {});

type Options = {
  width?: number,
  height?: number,
  format: "png" | "jpg" | "webm",
  quality: number,
  result: "tmpfile" | "base64" | "data-uri",
  snapshotContentContainer: boolean
};

if (!RNViewShot) {
  console.warn(
    "NativeModules.RNViewShot is undefined. Make sure the library is linked on the native side."
  );
}

const acceptedFormats = ["png", "jpg"].concat(
  Platform.OS === "android" ? ["webm"] : []
);

const acceptedResults = ["tmpfile", "base64", "data-uri"];

const defaultOptions = {
  format: "png",
  quality: 1,
  result: "tmpfile",
  snapshotContentContainer: false
};

// validate and coerce options
function validateOptions(
  options: ?Object
): { options: Options, errors: Array<string> } {
  options = {
    ...defaultOptions,
    ...options
  };
  const errors = [];
  if (
    "width" in options &&
    (typeof options.width !== "number" || options.width <= 0)
  ) {
    errors.push("option width should be a positive number");
    delete options.width;
  }
  if (
    "height" in options &&
    (typeof options.height !== "number" || options.height <= 0)
  ) {
    errors.push("option height should be a positive number");
    delete options.height;
  }
  if (
    typeof options.quality !== "number" ||
    options.quality < 0 ||
    options.quality > 1
  ) {
    errors.push("option quality should be a number between 0.0 and 1.0");
    options.quality = defaultOptions.quality;
  }
  if (typeof options.snapshotContentContainer !== "boolean") {
    errors.push("option snapshotContentContainer should be a boolean");
  }
  if (acceptedFormats.indexOf(options.format) === -1) {
    options.format = defaultOptions.format;
    errors.push(
      "option format is not in valid formats: " + acceptedFormats.join(" | ")
    );
  }
  if (acceptedResults.indexOf(options.result) === -1) {
    options.result = defaultOptions.result;
    errors.push(
      "option result is not in valid formats: " + acceptedResults.join(" | ")
    );
  }
  return { options, errors };
}

export function captureRef(
  view: number | ReactElement<*>,
  optionsObject?: Object
): Promise<string> {
  if (typeof view !== "number") {
    const node = findNodeHandle(view);
    if (!node)
      return Promise.reject(
        new Error("findNodeHandle failed to resolve view=" + String(view))
      );
    view = node;
  }
  const { options, errors } = validateOptions(optionsObject);
  if (__DEV__ && errors.length > 0) {
    console.warn(
      "react-native-view-shot: bad options:\n" +
        errors.map(e => `- ${e}`).join("\n")
    );
  }
  return RNViewShot.captureRef(view, options);
}

export function releaseCapture(uri: string): void {
  if (typeof uri !== "string") {
    if (__DEV__) {
      console.warn("Invalid argument to releaseCapture. Got: " + uri);
    }
  } else {
    RNViewShot.releaseCapture(uri);
  }
}

export function captureScreen(
  optionsObject?: Options
): Promise<string> {
  const { options, errors } = validateOptions(optionsObject);
  if (__DEV__ && errors.length > 0) {
    console.warn(
      "react-native-view-shot: bad options:\n" +
        errors.map(e => `- ${e}`).join("\n")
    );
  }
  return RNViewShot.captureScreen(options);
}

type Props = {
  options?: Object,
  captureMode?: "mount" | "continuous" | "update",
  children: React.Element<*>,
  onLayout?: (e: *) => void,
  onCapture?: (uri: string) => void,
  onCaptureFailure?: (e: Error) => void
};

function checkCompatibleProps(props: Props) {
  if (!props.captureMode && props.onCapture) {
    console.warn(
      "react-native-view-shot: a captureMode prop must be provided for `onCapture`"
    );
  } else if (props.captureMode && !props.onCapture) {
    console.warn(
      "react-native-view-shot: captureMode prop is defined but onCapture prop callback is missing"
    );
  } else if (
    (props.captureMode === "continuous" || props.captureMode === "update") &&
    props.options &&
    props.options.result &&
    props.options.result !== "tmpfile"
  ) {
    console.warn(
      "react-native-view-shot: result=tmpfile is recommended for captureMode=" +
        props.captureMode
    );
  }
}

export default class ViewShot extends Component {
  static captureRef = captureRef;
  static releaseCapture = releaseCapture;
  props: Props;
  root: ?View;

  _raf: *;
  lastCapturedURI: ?string;

  resolveFirstLayout: (layout: Object) => void;
  firstLayoutPromise = new Promise(resolve => {
    this.resolveFirstLayout = resolve;
  });

  capture = (): Promise<string> =>
    this.firstLayoutPromise
      .then(() => {
        const { root } = this;
        if (!root) return neverEndingPromise; // component is unmounted, you never want to hear back from the promise
        return captureRef(root, this.props.options);
      })
      .then(
        (uri: string) => {
          this.onCapture(uri);
          return uri;
        },
        (e: Error) => {
          this.onCaptureFailure(e);
          throw e;
        }
      );

  onCapture = (uri: string) => {
    if (!this.root) return;
    if (this.lastCapturedURI) {
      // schedule releasing the previous capture
      setTimeout(releaseCapture, 500, this.lastCapturedURI);
    }
    this.lastCapturedURI = uri;
    const { onCapture } = this.props;
    if (onCapture) onCapture(uri);
  };

  onCaptureFailure = (e: Error) => {
    if (!this.root) return;
    const { onCaptureFailure } = this.props;
    if (onCaptureFailure) onCaptureFailure(e);
  };

  syncCaptureLoop = (captureMode: ?string) => {
    cancelAnimationFrame(this._raf);
    if (captureMode === "continuous") {
      let previousCaptureURI = "-"; // needs to capture at least once at first, so we use "-" arbitrary string
      const loop = () => {
        this._raf = requestAnimationFrame(loop);
        if (previousCaptureURI === this.lastCapturedURI) return; // previous capture has not finished, don't capture yet
        previousCaptureURI = this.lastCapturedURI;
        this.capture();
      };
      this._raf = requestAnimationFrame(loop);
    }
  };

  onRef = (ref: View) => {
    this.root = ref;
  };

  onLayout = (e: { nativeEvent: { layout: Object } }) => {
    const { onLayout } = this.props;
    this.resolveFirstLayout(e.nativeEvent.layout);
    if (onLayout) onLayout(e);
  };

  componentDidMount() {
    if (__DEV__) checkCompatibleProps(this.props);
    if (this.props.captureMode === "mount") {
      this.capture();
    } else {
      this.syncCaptureLoop(this.props.captureMode);
    }
  }

  componentWillReceiveProps(nextProps: Props) {
    if (nextProps.captureMode !== this.props.captureMode) {
      this.syncCaptureLoop(nextProps.captureMode);
    }
  }

  componentDidUpdate() {
    if (this.props.captureMode === "update") {
      this.capture();
    }
  }

  componentWillUnmount() {
    this.syncCaptureLoop(null);
  }

  render() {
    const { children } = this.props;
    return (
      <View ref={this.onRef} collapsable={false} onLayout={this.onLayout}>
        {children}
      </View>
    );
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import welcomeReducer from './Welcome/reducers'
import Welcome from './Welcome'
import registerServiceWorker from './registerServiceWorker'
import 'semantic-ui-css/semantic.min.css'
import './index.css'

let store = createStore(welcomeReducer)

ReactDOM.render(
  <Provider store={store}><Welcome /></Provider>,
  document.getElementById('root')
)
registerServiceWorker()
<commit_msg>Add hot module reload<commit_after>import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import welcomeReducer from './Welcome/reducers'
import Welcome from './Welcome'
import registerServiceWorker from './registerServiceWorker'
import 'semantic-ui-css/semantic.min.css'
import './index.css'

let store = createStore(welcomeReducer)

ReactDOM.render(
  <Provider store={store}><Welcome /></Provider>,
  document.getElementById('root')
)
registerServiceWorker()

if (module.hot) {
  module.hot.accept()
}
<|endoftext|>