<commit_before>/*!
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) 2011-2017, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Utils, API, Window) {
  'use strict';

  /**
   * A callback for Dialogs.
   *
   *

   * The list of included buttons are: ok, cancel, yes, no
   * depending on which dialog was called.
   *
   * The result also depends on which dialog was called.
   *
   * The default button is 'cancel' if window was closed.
   *
   * You only get an event back if an actual button was pressed.
   *

   *
   * @callback CallbackDialog
   * @param {Event}   ev      Browser event that occured from action
   * @param {String}  button  Which button that was clicked
   * @param {Mixed}   result  Result from dialog input
   */

  /////////////////////////////////////////////////////////////////////////////
  // DIALOG
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Dialog Window
   *
   * A simple wrapper with some pre-defined options
   *
   *

   * YOU CANNOT CANNOT USE THIS VIA 'new' KEYWORD.
   *

   *
   * @summary Class used for basis as a Dialog.
   *
   * @param {String}          className     Dialog Class Name
   * @param {Object}          opts          Dialog Class Options
   * @param {Object}          args          Dialog Class Arguments
   * @param {CallbackDialog}  callback      Callback function
   *
   * @abstract
   * @constructor
   * @memberof OSjs.Core
   * @extends OSjs.Core.Window
   * @see OSjs.API.createDialog
   */
  function DialogWindow(className, opts, args, callback) {
    var self = this;

    opts = opts || {};
    args = args || {};

    callback = callback || function() {};
    if ( typeof callback !== 'function' ) {
      throw new TypeError('DialogWindow expects a callback Function, gave: ' + typeof callback);
    }

    console.info('DialogWindow::construct()', className, opts, args);

    Window.apply(this, [className, opts]);

    this._properties.gravity          = 'center';
    this._properties.allow_resize     = false;
    this._properties.allow_minimize   = false;
    this._properties.allow_maximize   = false;
    this._properties.allow_windowlist = false;
    this._properties.allow_session    = false;
    this._state.ontop                 = true;
    this._tag                         = 'DialogWindow';

    if ( args.scheme && args.scheme instanceof OSjs.GUI.Scheme ) {
      this.scheme = args.scheme;
      delete args.scheme;
    } else {
      this.scheme = OSjs.GUI.DialogScheme.get();
    }

    this.args = args;
    this.className = className;
    this.buttonClicked = false;

    this.closeCallback = function Dialog_closeCallback(ev, button, result) {
      if ( self._destroyed ) {
        return;
      }

      self.buttonClicked = true;
      callback.apply(self, arguments);
      self._close();
    };
  }

  DialogWindow.prototype = Object.create(Window.prototype);
  DialogWindow.constructor = Window;

  /**
   * @override
   * @function init
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype.init = function() {
    var self = this;

    var root = Window.prototype.init.apply(this, arguments);
    root.setAttribute('role', 'dialog');

    this.scheme.render(this, this.className.replace(/Dialog$/, ''), root, 'application-dialog', function(node) {
      node.querySelectorAll('gui-label').forEach(function(el) {
        if ( el.childNodes.length && el.childNodes[0].nodeType === 3 && el.childNodes[0].nodeValue ) {
          var label = el.childNodes[0].nodeValue;
          Utils.$empty(el);
          el.appendChild(document.createTextNode(API._(label)));
        }
      });
    });

    var buttonMap = {
      ButtonOK: 'ok',
      ButtonCancel: 'cancel',
      ButtonYes: 'yes',
      ButtonNo: 'no'
    };

    var focusButtons = ['ButtonCancel', 'ButtonNo'];

    Object.keys(buttonMap).forEach(function(id) {
      if ( self._findDOM(id) ) {
        var btn = self._find(id);
        btn.on('click', function(ev) {
          self.onClose(ev, buttonMap[id]);
        });
        if ( focusButtons.indexOf(id) >= 0 ) {
          btn.focus();
        }
      }
    });

    Utils.$addClass(root, 'DialogWindow');

    return root;
  };

  /**
   * When dialog closes
   *
   * @param   {Event}     ev        DOM Event
   * @param   {String}    button    Button used
   *
   * @function onClose
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype.onClose = function(ev, button) {
    this.closeCallback(ev, button, null);
  };

  /**
   * @override
   * @function _close
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype._close = function() {
    if ( !this.buttonClicked ) {
      this.onClose(null, 'cancel', null);
    }
    return Window.prototype._close.apply(this, arguments);
  };

  /**
   * @override
   * @function _onKeyEvent
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype._onKeyEvent = function(ev) {
    Window.prototype._onKeyEvent.apply(this, arguments);

    if ( ev.keyCode === Utils.Keys.ESC ) {
      this.onClose(ev, 'cancel');
    }
  };

  /**
   * Parses given message to be inserted into Dialog
   *
   * @param {String}  msg   Message
   *
   * @return {DocumentFragment}
   *
   * @function parseMessage
   * @memberof OSjs.Core.DialogWindow
   */
  DialogWindow.parseMessage = function(msg) {
    msg = Utils.$escape(msg || '').replace(/\*\*(.*)\*\*/g, '$1');

    var tmp = document.createElement('div');
    tmp.innerHTML = msg;

    var frag = document.createDocumentFragment();
    for ( var i = 0; i < tmp.childNodes.length; i++ ) {
      frag.appendChild(tmp.childNodes[i].cloneNode(true));
    }
    tmp = null;

    return frag;
  };

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Core.DialogWindow = Object.seal(DialogWindow);

})(OSjs.Utils, OSjs.API, OSjs.Core.Window);
<commit_msg>Dialogs: Allow unsetting scheme for custom dialogs<commit_after>/*!
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) 2011-2017, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Utils, API, Window) {
  'use strict';

  /**
   * A callback for Dialogs.
   *
   *

   * The list of included buttons are: ok, cancel, yes, no
   * depending on which dialog was called.
   *
   * The result also depends on which dialog was called.
   *
   * The default button is 'cancel' if window was closed.
   *
   * You only get an event back if an actual button was pressed.
   *

   *
   * @callback CallbackDialog
   * @param {Event}   ev      Browser event that occured from action
   * @param {String}  button  Which button that was clicked
   * @param {Mixed}   result  Result from dialog input
   */

  /////////////////////////////////////////////////////////////////////////////
  // DIALOG
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Dialog Window
   *
   * A simple wrapper with some pre-defined options
   *
   *

   * YOU CANNOT CANNOT USE THIS VIA 'new' KEYWORD.
   *

   *
   * @summary Class used for basis as a Dialog.
   *
   * @param {String}          className     Dialog Class Name
   * @param {Object}          opts          Dialog Class Options
   * @param {Object}          args          Dialog Class Arguments
   * @param {CallbackDialog}  callback      Callback function
   *
   * @abstract
   * @constructor
   * @memberof OSjs.Core
   * @extends OSjs.Core.Window
   * @see OSjs.API.createDialog
   */
  function DialogWindow(className, opts, args, callback) {
    var self = this;

    opts = opts || {};
    args = args || {};

    callback = callback || function() {};
    if ( typeof callback !== 'function' ) {
      throw new TypeError('DialogWindow expects a callback Function, gave: ' + typeof callback);
    }

    console.info('DialogWindow::construct()', className, opts, args);

    Window.apply(this, [className, opts]);

    this._properties.gravity          = 'center';
    this._properties.allow_resize     = false;
    this._properties.allow_minimize   = false;
    this._properties.allow_maximize   = false;
    this._properties.allow_windowlist = false;
    this._properties.allow_session    = false;
    this._state.ontop                 = true;
    this._tag                         = 'DialogWindow';

    if ( args.scheme && args.scheme instanceof OSjs.GUI.Scheme ) {
      this.scheme = args.scheme;
      delete args.scheme;
    } else {
      this.scheme = OSjs.GUI.DialogScheme.get();
    }

    this.args = args;
    this.className = className;
    this.buttonClicked = false;

    this.closeCallback = function Dialog_closeCallback(ev, button, result) {
      if ( self._destroyed ) {
        return;
      }

      self.buttonClicked = true;
      callback.apply(self, arguments);
      self._close();
    };
  }

  DialogWindow.prototype = Object.create(Window.prototype);
  DialogWindow.constructor = Window;

  /**
   * @override
   * @function init
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype.init = function() {
    var self = this;

    var root = Window.prototype.init.apply(this, arguments);
    root.setAttribute('role', 'dialog');

    if ( this.scheme ) {
      this.scheme.render(this, this.className.replace(/Dialog$/, ''), root, 'application-dialog', function(node) {
        node.querySelectorAll('gui-label').forEach(function(el) {
          if ( el.childNodes.length && el.childNodes[0].nodeType === 3 && el.childNodes[0].nodeValue ) {
            var label = el.childNodes[0].nodeValue;
            Utils.$empty(el);
            el.appendChild(document.createTextNode(API._(label)));
          }
        });
      });

      var buttonMap = {
        ButtonOK: 'ok',
        ButtonCancel: 'cancel',
        ButtonYes: 'yes',
        ButtonNo: 'no'
      };

      var focusButtons = ['ButtonCancel', 'ButtonNo'];

      Object.keys(buttonMap).forEach(function(id) {
        if ( self._findDOM(id) ) {
          var btn = self._find(id);
          btn.on('click', function(ev) {
            self.onClose(ev, buttonMap[id]);
          });
          if ( focusButtons.indexOf(id) >= 0 ) {
            btn.focus();
          }
        }
      });
    }

    Utils.$addClass(root, 'DialogWindow');

    return root;
  };

  /**
   * When dialog closes
   *
   * @param   {Event}     ev        DOM Event
   * @param   {String}    button    Button used
   *
   * @function onClose
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype.onClose = function(ev, button) {
    this.closeCallback(ev, button, null);
  };

  /**
   * @override
   * @function _close
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype._close = function() {
    if ( !this.buttonClicked ) {
      this.onClose(null, 'cancel', null);
    }
    return Window.prototype._close.apply(this, arguments);
  };

  /**
   * @override
   * @function _onKeyEvent
   * @memberof OSjs.Core.DialogWindow#
   */
  DialogWindow.prototype._onKeyEvent = function(ev) {
    Window.prototype._onKeyEvent.apply(this, arguments);

    if ( ev.keyCode === Utils.Keys.ESC ) {
      this.onClose(ev, 'cancel');
    }
  };

  /**
   * Parses given message to be inserted into Dialog
   *
   * @param {String}  msg   Message
   *
   * @return {DocumentFragment}
   *
   * @function parseMessage
   * @memberof OSjs.Core.DialogWindow
   */
  DialogWindow.parseMessage = function(msg) {
    msg = Utils.$escape(msg || '').replace(/\*\*(.*)\*\*/g, '$1');

    var tmp = document.createElement('div');
    tmp.innerHTML = msg;

    var frag = document.createDocumentFragment();
    for ( var i = 0; i < tmp.childNodes.length; i++ ) {
      frag.appendChild(tmp.childNodes[i].cloneNode(true));
    }
    tmp = null;

    return frag;
  };

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Core.DialogWindow = Object.seal(DialogWindow);

})(OSjs.Utils, OSjs.API, OSjs.Core.Window);
<|endoftext|>


<commit_before>'use strict'

const Speedtest = require('../models/speedtest');

module.exports.index = (req, res) => {
  res.send('I exist');
};

module.exports.new = (req, res) => {
  const obj = new Speedtest({
    date: req.body.date,
    download: req.body.download,
    upload: req.body.upload
  });

  obj.save((err, newObj) => {
    if (err) throw err;
    res.send(newObj);
  });
};
<commit_msg>Added ping to speedtest creation post handler<commit_after>'use strict'

const Speedtest = require('../models/speedtest');

module.exports.index = (req, res) => {
  res.send('I exist');
};

module.exports.new = (req, res) => {
  const obj = new Speedtest({
    date: req.body.date,
    ping: req.body.ping,
    download: req.body.download,
    upload: req.body.upload
  });

  obj.save((err, newObj) => {
    if (err) throw err;
    res.send(newObj);
  });
};
<|endoftext|>


<commit_before>// Required
var Config   = require('./config/Config.json');
var Twitter  = require('./config/Twitter.js')
var Mongo    = require('./config/Mongo.js')
var Util     = require('util')
var Colors   = require('colors')
var FS       = require('fs')
var PathUtil = require('path')
var Http     = require('http-get')
//

Mongo.db.on('error', console.error.bind(console, 'connection error:'));
Mongo.db.once('open', function callback () {
	console.log('Mongoose : OK'.green);
	checkTwitterOk();
});

function checkTwitterOk() {
	Twitter.verifyCredentials(function (err, data) {
		if (err) {
			console.error(err);
		}
		else {
			var welcomeMessage = 'Logged as ' + data.name + ' (' + data.screen_name + ')';
			console.log(welcomeMessage.cyan);
			initStream();
		}
	});
};

function initStream () {
	Twitter.stream('user', {'with':'followings'}, function(stream) {
		console.log('Stream : OK'.green);
		console.log('Waiting for a new tweet...'.green);
		stream.on('data', function (data) {
			if (data.text !== undefined) {
				displayStream(data);
				saveStream(data);
			}
		});
		stream.on('end', function (response) {
			console.log("Disconnection detected. Initializing a new stream...")
			console.log(response.red);
  			initStream();
		});
		stream.on('destroy', function (response) {
			console.log("Silent disconnection detected. Initializing a new stream...")
			console.log(response.red);
  			initStream();
		});
	});
}

function displayStream(data) {
	// Display in console [DATE] @XXXXX : TWEET
	var date  = data.created_at
	var user  = data.user.screen_name
	var tweet = data.text
	// Format like we want
	var f_date  = '[' + date + '] : '
	var f_user  = '@' + user
	var f_tweet = ' ' + tweet
	console.log(f_date.bold.white + f_user.cyan + f_tweet.yellow)
}

function saveStream(data) {
	var tweet = new Mongo.Tweet({
			created_at: data.created_at,
			id: data.id,
			id_str: data.id_str,
			text: data.text,
			source: data.source,
			truncated: data.truncated,
			in_reply_to_status_id: data.in_reply_to_status_id,
			in_reply_to_status_id_str: data.in_reply_to_status_id_str,
			in_reply_to_user_id: data.in_reply_to_user_id,
			in_reply_to_user_id_str: data.in_reply_to_user_id_str,
			in_reply_to_screen_name: data.in_reply_to_screen_name,
			user : {
				id: data.user.id,
				id_str: data.user.id_str,
				name: data.user.name,
				screen_name: data.user.screen_name,
				location: data.user.location,
				url: data.user.url,
				description: data.user.description,
				protected: data.user.protected,
				followers_count: data.user.followers_count,
				friends_count: data.user.friends_count,
				listed_count: data.user.listed_count,
				created_at: data.user.created_at,
				favourites_count: data.user.favourites_count,
				utc_offset: data.user.utc_offset,
				time_zone: data.user.time_zone,
				geo_enabled: data.user.geo_enabled,
				verified: data.user.verified,
				statuses_count: data.user.statuses_count,
				lang: data.user.lang,
				contributors_enabled: data.user.contributors_enabled,
				is_translator: data.user.is_translator,
				profile_background_color: data.user.profile_background_color,
				profile_background_image_url: data.user.profile_background_image_url,
				profile_background_image_url_https: data.user.profile_background_image_url_https,
				profile_background_tile: data.user.profile_background_tile,
				profile_image_url: data.user.profile_image_url,
				profile_image_url_https: data.user.profile_image_url_https,
				profile_banner_url: data.user.profile_banner_url,
				profile_link_color: data.user.profile_link_color,
				profile_sidebar_border_color: data.user.profile_sidebar_border_color,
				profile_sidebar_fill_color: data.user.profile_sidebar_fill_color,
				profile_text_color: data.user.profile_text_color,
				profile_use_background_image: data.user.profile_use_background_image,
				default_profile: data.user.default_profile,
				default_profile_image: data.user.default_profile_image,
				following: data.user.following,
				follow_request_sent: data.user.follow_request_sent,
				notifications: data.user.notifications
			},
			coordinates: data.coordinates,
			place: data.place,
			contributors: data.contributors,
			retweet_count: data.retweet_count,
			favorite_count: data.favorite_count,
			entities: {
				hashtags: data.entities.hashtags,
				symbols: data.entities.symbols,
				urls: data.entities.urls,
				user_mentions: data.entities.user_mentions,
				media: data.entities.media
			},
			favorited: data.favorited,
			retweeted: data.retweeted,
			possibly_sensitive: data.possibly_sensitive,
			filter_level: data.filter_level,
			lang: data.lang
		})
	tweet.save(function (err, tweet) {
	  if (err) {
	  	console.log(err.red)
	  }
	});
	if (data.entities.media !== undefined) {
		saveMedia(data.entities.media, data.user)
	}
}

function saveMedia(medias, user) {
	medias.forEach(function (media) { // foreach medias posted
		var mediaLink   = media.media_url_https + ':large'; // we add :large to get a better quality
		var base_folder = Config.basePath || './pictures';
		var path_folder = PathUtil.join(base_folder, user.screen_name);

		// Verify if base folder exists (basefolder = BASEFOLDER/usernameTwitter/pic.jpg)
		FS.exists(base_folder, function(exists) {
			// if the folder where we should save images doesn't exists (the one with the username)
			if(!exists) {
				// we create it
				FS.mkdir(base_folder, function(err) {
					if(err) {
						console.error(base_folder);
						console.error(err.red);
					}
				});
			}
		});

		FS.exists(path_folder, function(exists) {
			// if the folder where we should save images doesn't exists (the one with the username)
			if(!exists) {
				// we create it
				FS.mkdir(path_folder, function(err) {
					if(err) {
						console.error(path_folder);
						console.error(err.red);
					}
					// or we download the file in it
					else {
						download();
					}
				});
			}
			else {
				download();
			}
		});

		function download() {
			var path = PathUtil.join(path_folder, media.id_str + '.jpg');
			Http.get(mediaLink, path, function (error, result) { // Function to save this image
				if (error) {
					console.error(error.red);
				}
				else {
					console.log('File downloaded at: ' + result.file.green);
				}
			});
		}
	});
}<commit_msg>attempt to fix disconnections<commit_after>// Required
var Config   = require('./config/Config.json');
var Twitter  = require('./config/Twitter.js')
var Mongo    = require('./config/Mongo.js')
var Util     = require('util')
var Colors   = require('colors')
var FS       = require('fs')
var PathUtil = require('path')
var Http     = require('http-get')
//

Mongo.db.on('error', console.error.bind(console, 'connection error:'));
Mongo.db.once('open', function callback () {
	console.log('Mongoose : OK'.green);
	checkTwitterOk();
});

function checkTwitterOk() {
	Twitter.verifyCredentials(function (err, data) {
		if (err) {
			console.error(err);
		}
		else {
			var welcomeMessage = 'Logged as ' + data.name + ' (' + data.screen_name + ')';
			console.log(welcomeMessage.cyan);
			initStream();
		}
	});
};

function initStream () {
	Twitter.stream('user', {'with':'followings'}, function(stream) {
		console.log('Stream : OK'.green);
		console.log('Waiting for a new tweet...'.green);
		stream.on('data', function (data) {
			if (data.text !== undefined) {
				displayStream(data);
				saveStream(data);
			}
		});
		stream.on('end', function (response) {
			console.log("Disconnection detected. Initializing a new stream...")
			console.log(response.red);
  			checkTwitterOk();
		});
		stream.on('destroy', function (response) {
			console.log("Silent disconnection detected. Initializing a new stream...")
			console.log(response.red);
  			checkTwitterOk();
		});
	});
}

function displayStream(data) {
	// Display in console [DATE] @XXXXX : TWEET
	var date  = data.created_at
	var user  = data.user.screen_name
	var tweet = data.text
	// Format like we want
	var f_date  = '[' + date + '] : '
	var f_user  = '@' + user
	var f_tweet = ' ' + tweet
	console.log(f_date.bold.white + f_user.cyan + f_tweet.yellow)
}

function saveStream(data) {
	var tweet = new Mongo.Tweet({
			created_at: data.created_at,
			id: data.id,
			id_str: data.id_str,
			text: data.text,
			source: data.source,
			truncated: data.truncated,
			in_reply_to_status_id: data.in_reply_to_status_id,
			in_reply_to_status_id_str: data.in_reply_to_status_id_str,
			in_reply_to_user_id: data.in_reply_to_user_id,
			in_reply_to_user_id_str: data.in_reply_to_user_id_str,
			in_reply_to_screen_name: data.in_reply_to_screen_name,
			user : {
				id: data.user.id,
				id_str: data.user.id_str,
				name: data.user.name,
				screen_name: data.user.screen_name,
				location: data.user.location,
				url: data.user.url,
				description: data.user.description,
				protected: data.user.protected,
				followers_count: data.user.followers_count,
				friends_count: data.user.friends_count,
				listed_count: data.user.listed_count,
				created_at: data.user.created_at,
				favourites_count: data.user.favourites_count,
				utc_offset: data.user.utc_offset,
				time_zone: data.user.time_zone,
				geo_enabled: data.user.geo_enabled,
				verified: data.user.verified,
				statuses_count: data.user.statuses_count,
				lang: data.user.lang,
				contributors_enabled: data.user.contributors_enabled,
				is_translator: data.user.is_translator,
				profile_background_color: data.user.profile_background_color,
				profile_background_image_url: data.user.profile_background_image_url,
				profile_background_image_url_https: data.user.profile_background_image_url_https,
				profile_background_tile: data.user.profile_background_tile,
				profile_image_url: data.user.profile_image_url,
				profile_image_url_https: data.user.profile_image_url_https,
				profile_banner_url: data.user.profile_banner_url,
				profile_link_color: data.user.profile_link_color,
				profile_sidebar_border_color: data.user.profile_sidebar_border_color,
				profile_sidebar_fill_color: data.user.profile_sidebar_fill_color,
				profile_text_color: data.user.profile_text_color,
				profile_use_background_image: data.user.profile_use_background_image,
				default_profile: data.user.default_profile,
				default_profile_image: data.user.default_profile_image,
				following: data.user.following,
				follow_request_sent: data.user.follow_request_sent,
				notifications: data.user.notifications
			},
			coordinates: data.coordinates,
			place: data.place,
			contributors: data.contributors,
			retweet_count: data.retweet_count,
			favorite_count: data.favorite_count,
			entities: {
				hashtags: data.entities.hashtags,
				symbols: data.entities.symbols,
				urls: data.entities.urls,
				user_mentions: data.entities.user_mentions,
				media: data.entities.media
			},
			favorited: data.favorited,
			retweeted: data.retweeted,
			possibly_sensitive: data.possibly_sensitive,
			filter_level: data.filter_level,
			lang: data.lang
		})
	tweet.save(function (err, tweet) {
	  if (err) {
	  	console.log(err.red)
	  }
	});
	if (data.entities.media !== undefined) {
		saveMedia(data.entities.media, data.user)
	}
}

function saveMedia(medias, user) {
	medias.forEach(function (media) { // foreach medias posted
		var mediaLink   = media.media_url_https + ':large'; // we add :large to get a better quality
		var base_folder = Config.basePath || './pictures';
		var path_folder = PathUtil.join(base_folder, user.screen_name);

		// Verify if base folder exists (basefolder = BASEFOLDER/usernameTwitter/pic.jpg)
		FS.exists(base_folder, function(exists) {
			// if the folder where we should save images doesn't exists (the one with the username)
			if(!exists) {
				// we create it
				FS.mkdir(base_folder, function(err) {
					if(err) {
						console.error(base_folder);
						console.error(err.red);
					}
				});
			}
		});

		FS.exists(path_folder, function(exists) {
			// if the folder where we should save images doesn't exists (the one with the username)
			if(!exists) {
				// we create it
				FS.mkdir(path_folder, function(err) {
					if(err) {
						console.error(path_folder);
						console.error(err.red);
					}
					// or we download the file in it
					else {
						download();
					}
				});
			}
			else {
				download();
			}
		});

		function download() {
			var path = PathUtil.join(path_folder, media.id_str + '.jpg');
			Http.get(mediaLink, path, function (error, result) { // Function to save this image
				if (error) {
					console.error(error.red);
				}
				else {
					console.log('File downloaded at: ' + result.file.green);
				}
			});
		}
	});
}<|endoftext|>


<commit_before>const path = require('path')
const db = require('sqlite')
const sql = require('sqlate')
const log = require('../lib/logger')('Library')
let _libraryVersion = Date.now()
let _starCountsVersion = Date.now()

class Library {
  /**
  * Get artists and songs in a format suitable for sending to clients.
  * Should not include songs or artists for which there are no media.
  *
  * @return {Promise} Object with artists and songs normalized
  */
  static async get () {
    const SongIdsByArtist = {}
    const artists = {
      result: [],
      entities: {}
    }
    const songs = {
      result: [],
      entities: {}
    }

    // query #1: songs
    {
      const query = sql`
        SELECT duration, isPreferred, songs.artistId AS artistId, songs.songId AS songId, songs.title AS title
        FROM media
          INNER JOIN songs USING (songId)
          INNER JOIN paths USING (pathId)
        ORDER BY songs.titleNorm, paths.priority ASC
      `
      const rows = await db.all(String(query), query.parameters)

      for (const row of rows) {
        if (songs.entities[row.songId]) {
          if (row.isPreferred) {
            songs.entities[row.songId].duration = row.duration
          }

          songs.entities[row.songId].numMedia++
          continue
        }

        delete row.isPreferred // no need to send over the wire
        songs.entities[row.songId] = row
        songs.entities[row.songId].numMedia = 1
        songs.result.push(row.songId)

        // add to artist's songIds
        if (typeof SongIdsByArtist[row.artistId] === 'undefined') {
          SongIdsByArtist[row.artistId] = []
        }

        SongIdsByArtist[row.artistId].push(row.songId)
      }
    }

    // query #2: artists
    {
      const query = sql`
        SELECT *
        FROM artists
        ORDER BY nameNorm ASC
      `
      const rows = await db.all(String(query), query.parameters)

      for (const row of rows) {
        if (SongIdsByArtist[row.artistId]) {
          artists.result.push(row.artistId)
          artists.entities[row.artistId] = row
          artists.entities[row.artistId].songIds = SongIdsByArtist[row.artistId]
        }
      }
    }

    return {
      artists,
      songs,
      version: Library.getLibraryVersion(),
    }
  }

  /**
  * Matches or creates artist and song
  *
  * @param  {object}  parsed  The object returned from MetaParser
  * @return {object}          { artistId, songId }
  */
  static async matchSong (parsed) {
    const match = {}

    // match artist
    {
      const query = sql`
        SELECT *
        FROM artists
        WHERE nameNorm = ${parsed.artistNorm}
      `
      const row = await db.get(String(query), query.parameters)

      if (row) {
        // log.info('matched artist: %s', row.name)
        match.artistId = row.artistId
        match.artist = row.name
        match.artistNorm = row.nameNorm
      } else {
        log.info('new artist: %s', parsed.artist)

        const fields = new Map()
        fields.set('name', parsed.artist)
        fields.set('nameNorm', parsed.artistNorm)

        const query = sql`
          INSERT INTO artists ${sql.tuple(Array.from(fields.keys()).map(sql.column))}
          VALUES ${sql.tuple(Array.from(fields.values()))}
        `
        const res = await db.run(String(query), query.parameters)

        if (!Number.isInteger(res.stmt.lastID)) {
          throw new Error('invalid artistId after insert')
        }

        match.artistId = res.stmt.lastID
        match.artist = parsed.artist
        match.artistNorm = parsed.artistNorm
      }
    }

    // match song title
    {
      const query = sql`
        SELECT *
        FROM songs
        WHERE artistId = ${match.artistId} AND titleNorm = ${parsed.titleNorm}
      `
      const row = await db.get(String(query), query.parameters)

      if (row) {
        // log.info('matched song: %s', row.title)
        match.songId = row.songId
        match.title = row.title
        match.titleNorm = row.titleNorm
      } else {
        log.info('new song: %s', parsed.title)

        const fields = new Map()
        fields.set('artistId', match.artistId)
        fields.set('title', parsed.title)
        fields.set('titleNorm', parsed.titleNorm)

        const query = sql`
          INSERT INTO songs ${sql.tuple(Array.from(fields.keys()).map(sql.column))}
          VALUES ${sql.tuple(Array.from(fields.values()))}
        `
        const res = await db.run(String(query), query.parameters)

        if (!Number.isInteger(res.stmt.lastID)) {
          throw new Error('invalid songId after insert')
        }

        match.songId = res.stmt.lastID
        match.title = parsed.title
        match.titleNorm = parsed.titleNorm
      }
    }

    return match
  }

  /**
  * Get underlying media for a given song
  *
  * @param  {number}  songId
  * @return {Promise} normalized media entries
  */
  static async getSong (songId) {
    const media = {
      result: [],
      entities: {},
    }

    const query = sql`
      SELECT media.*, paths.path, songs.artistId, songs.songId, songs.title
      FROM media
        INNER JOIN (
          SELECT *
          FROM paths
          GROUP BY pathId
        ) paths ON (paths.pathId = media.pathId)
        INNER JOIN songs USING (songId)
        INNER JOIN artists USING (artistId)
      WHERE songId = ${songId}
      ORDER BY paths.priority ASC
    `
    const rows = await db.all(String(query), query.parameters)

    rows.forEach(row => {
      media.result.push(row.mediaId)

      row.file = row.path + path.sep + row.relPath
      media.entities[row.mediaId] = row
    })

    return media
  }

  /**
  * Gets a user's starred artists and songs
  *
  * @param  {Number}  userId
  * @return {Object}
  */
  static async getStars (userId) {
    let starredArtists, starredSongs

    // get starred artists
    {
      const query = sql`
        SELECT artistId
        FROM artistStars
        WHERE userId = ${userId}
      `
      const rows = await db.all(String(query), query.parameters)

      starredArtists = rows.map(row => row.artistId)
    }

    // get starred songs
    {
      const query = sql`
        SELECT songId
        FROM songStars
        WHERE userId = ${userId}
      `
      const rows = await db.all(String(query), query.parameters)

      starredSongs = rows.map(row => row.songId)
    }

    return { starredArtists, starredSongs }
  }

  /**
  * Gets artist and song star counts
  *
  * @return {Object}
  */
  static async getStarCounts () {
    const artists = {}
    const songs = {}

    // get artist star counts
    {
      const query = sql`
        SELECT artistId, COUNT(userId) AS count
        FROM artistStars
        GROUP BY artistId
      `
      const rows = await db.all(String(query), query.parameters)

      rows.forEach(row => { artists[row.artistId] = row.count })
    }

    // get song star counts
    {
      const query = sql`
        SELECT songId, COUNT(userId) AS count
        FROM songStars
        GROUP BY songId
      `
      const rows = await db.all(String(query), query.parameters)

      rows.forEach(row => { songs[row.songId] = row.count })
    }

    return {
      artists,
      songs,
      version: Library.getStarCountsVersion(),
    }
  }

  static getLibraryVersion () { return _libraryVersion }
  static setLibraryVersion () { _libraryVersion = Date.now() }
  static getStarCountsVersion () { return _starCountsVersion }
  static setStarCountsVersion () { _starCountsVersion = Date.now() }
}

module.exports = Library
<commit_msg>Don't include the normalized cols in result<commit_after>const path = require('path')
const db = require('sqlite')
const sql = require('sqlate')
const log = require('../lib/logger')('Library')
let _libraryVersion = Date.now()
let _starCountsVersion = Date.now()

class Library {
  /**
  * Get artists and songs in a format suitable for sending to clients.
  * Should not include songs or artists for which there are no media.
  *
  * @return {Promise} Object with artists and songs normalized
  */
  static async get () {
    const SongIdsByArtist = {}
    const artists = {
      result: [],
      entities: {}
    }
    const songs = {
      result: [],
      entities: {}
    }

    // query #1: songs
    {
      const query = sql`
        SELECT duration, isPreferred, songs.artistId AS artistId, songs.songId AS songId, songs.title AS title
        FROM media
          INNER JOIN songs USING (songId)
          INNER JOIN paths USING (pathId)
        ORDER BY songs.titleNorm, paths.priority ASC
      `
      const rows = await db.all(String(query), query.parameters)

      for (const row of rows) {
        if (songs.entities[row.songId]) {
          if (row.isPreferred) {
            songs.entities[row.songId].duration = row.duration
          }

          songs.entities[row.songId].numMedia++
          continue
        }

        delete row.isPreferred // no need to send over the wire
        songs.entities[row.songId] = row
        songs.entities[row.songId].numMedia = 1
        songs.result.push(row.songId)

        // add to artist's songIds
        if (typeof SongIdsByArtist[row.artistId] === 'undefined') {
          SongIdsByArtist[row.artistId] = []
        }

        SongIdsByArtist[row.artistId].push(row.songId)
      }
    }

    // query #2: artists
    {
      const query = sql`
        SELECT artistId, name
        FROM artists
        ORDER BY nameNorm ASC
      `
      const rows = await db.all(String(query), query.parameters)

      for (const row of rows) {
        if (SongIdsByArtist[row.artistId]) {
          artists.result.push(row.artistId)
          artists.entities[row.artistId] = row
          artists.entities[row.artistId].songIds = SongIdsByArtist[row.artistId]
        }
      }
    }

    return {
      artists,
      songs,
      version: Library.getLibraryVersion(),
    }
  }

  /**
  * Matches or creates artist and song
  *
  * @param  {object}  parsed  The object returned from MetaParser
  * @return {object}          { artistId, songId }
  */
  static async matchSong (parsed) {
    const match = {}

    // match artist
    {
      const query = sql`
        SELECT *
        FROM artists
        WHERE nameNorm = ${parsed.artistNorm}
      `
      const row = await db.get(String(query), query.parameters)

      if (row) {
        // log.info('matched artist: %s', row.name)
        match.artistId = row.artistId
        match.artist = row.name
        match.artistNorm = row.nameNorm
      } else {
        log.info('new artist: %s', parsed.artist)

        const fields = new Map()
        fields.set('name', parsed.artist)
        fields.set('nameNorm', parsed.artistNorm)

        const query = sql`
          INSERT INTO artists ${sql.tuple(Array.from(fields.keys()).map(sql.column))}
          VALUES ${sql.tuple(Array.from(fields.values()))}
        `
        const res = await db.run(String(query), query.parameters)

        if (!Number.isInteger(res.stmt.lastID)) {
          throw new Error('invalid artistId after insert')
        }

        match.artistId = res.stmt.lastID
        match.artist = parsed.artist
        match.artistNorm = parsed.artistNorm
      }
    }

    // match song title
    {
      const query = sql`
        SELECT *
        FROM songs
        WHERE artistId = ${match.artistId} AND titleNorm = ${parsed.titleNorm}
      `
      const row = await db.get(String(query), query.parameters)

      if (row) {
        // log.info('matched song: %s', row.title)
        match.songId = row.songId
        match.title = row.title
        match.titleNorm = row.titleNorm
      } else {
        log.info('new song: %s', parsed.title)

        const fields = new Map()
        fields.set('artistId', match.artistId)
        fields.set('title', parsed.title)
        fields.set('titleNorm', parsed.titleNorm)

        const query = sql`
          INSERT INTO songs ${sql.tuple(Array.from(fields.keys()).map(sql.column))}
          VALUES ${sql.tuple(Array.from(fields.values()))}
        `
        const res = await db.run(String(query), query.parameters)

        if (!Number.isInteger(res.stmt.lastID)) {
          throw new Error('invalid songId after insert')
        }

        match.songId = res.stmt.lastID
        match.title = parsed.title
        match.titleNorm = parsed.titleNorm
      }
    }

    return match
  }

  /**
  * Get underlying media for a given song
  *
  * @param  {number}  songId
  * @return {Promise} normalized media entries
  */
  static async getSong (songId) {
    const media = {
      result: [],
      entities: {},
    }

    const query = sql`
      SELECT media.*, paths.path, songs.artistId, songs.songId, songs.title
      FROM media
        INNER JOIN (
          SELECT *
          FROM paths
          GROUP BY pathId
        ) paths ON (paths.pathId = media.pathId)
        INNER JOIN songs USING (songId)
        INNER JOIN artists USING (artistId)
      WHERE songId = ${songId}
      ORDER BY paths.priority ASC
    `
    const rows = await db.all(String(query), query.parameters)

    rows.forEach(row => {
      media.result.push(row.mediaId)

      row.file = row.path + path.sep + row.relPath
      media.entities[row.mediaId] = row
    })

    return media
  }

  /**
  * Gets a user's starred artists and songs
  *
  * @param  {Number}  userId
  * @return {Object}
  */
  static async getStars (userId) {
    let starredArtists, starredSongs

    // get starred artists
    {
      const query = sql`
        SELECT artistId
        FROM artistStars
        WHERE userId = ${userId}
      `
      const rows = await db.all(String(query), query.parameters)

      starredArtists = rows.map(row => row.artistId)
    }

    // get starred songs
    {
      const query = sql`
        SELECT songId
        FROM songStars
        WHERE userId = ${userId}
      `
      const rows = await db.all(String(query), query.parameters)

      starredSongs = rows.map(row => row.songId)
    }

    return { starredArtists, starredSongs }
  }

  /**
  * Gets artist and song star counts
  *
  * @return {Object}
  */
  static async getStarCounts () {
    const artists = {}
    const songs = {}

    // get artist star counts
    {
      const query = sql`
        SELECT artistId, COUNT(userId) AS count
        FROM artistStars
        GROUP BY artistId
      `
      const rows = await db.all(String(query), query.parameters)

      rows.forEach(row => { artists[row.artistId] = row.count })
    }

    // get song star counts
    {
      const query = sql`
        SELECT songId, COUNT(userId) AS count
        FROM songStars
        GROUP BY songId
      `
      const rows = await db.all(String(query), query.parameters)

      rows.forEach(row => { songs[row.songId] = row.count })
    }

    return {
      artists,
      songs,
      version: Library.getStarCountsVersion(),
    }
  }

  static getLibraryVersion () { return _libraryVersion }
  static setLibraryVersion () { _libraryVersion = Date.now() }
  static getStarCountsVersion () { return _starCountsVersion }
  static setStarCountsVersion () { _starCountsVersion = Date.now() }
}

module.exports = Library
<|endoftext|>


<commit_before>/**
 * Created by EXTIGLGCORREAG on 13/05/2014.
 */
'use strict';
/*jslint unparam: true, indent: 4 */
var express = require('express');
// var path = require('path');
var bodyParser = require('body-parser');
var passport = require('passport');
var oauth2 = require('./libs/oauth2');
var config = require('./config');
var usersRoute = require('./routes/users');
var Mongoose = require('mongoose');
require('./libs/auth');

var app = express();
app.set('dbUrl', config.db[app.settings.env]);
app.set('apiPath', '/api/v' + config.api.latestVersion);
console.log('connected to: ' + app.get('dbUrl'));
// connect mongoose to the mongo dbUrl
// Mongoose.connect(app.get('dbUrl'));

app.use(bodyParser());

var port = process.env.PORT || config.server.port;

var router = express.Router();

app.post('/oauth/token', oauth2.token);

router.get('/', function (req, res) {
    res.send(200);
});

app.use(app.get('apiPath'), router);
app.use(app.get('apiPath'), usersRoute);
app.use('', router);

app.listen(port);
console.log('Magic happens on port: ' + port);

module.exports = app;<commit_msg>removed comment<commit_after>/**
 * Created by EXTIGLGCORREAG on 13/05/2014.
 */
'use strict';
/*jslint unparam: true, indent: 4 */
var express = require('express');
// var path = require('path');
var bodyParser = require('body-parser');
var passport = require('passport');
var oauth2 = require('./libs/oauth2');
var config = require('./config');
var usersRoute = require('./routes/users');
var Mongoose = require('mongoose');
require('./libs/auth');

var app = express();
app.set('dbUrl', config.db[app.settings.env]);
app.set('apiPath', '/api/v' + config.api.latestVersion);
console.log('connected to: ' + app.get('dbUrl'));
// Mongoose.connect(app.get('dbUrl'));

app.use(bodyParser());

var port = process.env.PORT || config.server.port;

var router = express.Router();

app.post('/oauth/token', oauth2.token);

router.get('/', function (req, res) {
    res.send(200);
});

app.use(app.get('apiPath'), router);
app.use(app.get('apiPath'), usersRoute);
app.use('', router);

app.listen(port);
console.log('Magic happens on port: ' + port);

module.exports = app;<|endoftext|>


<commit_before>import Q from 'q'
import google from 'googleapis'
const gcal = google.calendar('v3');

export default class CalendarAPI {

  static get DAYS_TO_SYNC() { return 10 }
  static get MAX_RESULTS() { return 1000 }

  /*
   * Store the auth client to use with api calls
   */

  setAuth(oauth) {
    this.oauth = oauth;
  }

  /*
   * Run the event sync process
   *  If we have a syncToken in storage, initial sync is done, so use it to fetch the changed items
   *  If we have a pageToken in storage, we're in the middle of a sync so grab the next page
   */

  _getQueryOptions(syncTokens) {

    const nextSyncToken = syncTokens.nextSyncToken;
    const nextPageToken = syncTokens.nextPageToken;

    var opts = {
      auth: this.oauth.client,
      calendarId: 'primary',
      maxResults: CalendarAPI.MAX_RESULTS,
      timeZone: 'GMT',
      singleEvents: true
    }

    if (nextSyncToken) {
      opts.syncToken = nextSyncToken;
    } else if (!nextPageToken) {
      var start = new Date();
      start.setHours(0);
      start.setMinutes(0);
      start.setSeconds(0);
      var end = new Date(start);
      end.setDate(end.getDate() + CalendarAPI.DAYS_TO_SYNC);
      opts.timeMin = start.toISOString();
      opts.timeMax = end.toISOString();
    }

    if (nextPageToken) {
      opts.pageToken = nextPageToken;
    }

    return opts;
  }

  async syncEvents(syncTokens, collector={ save: [], remove: [] }) {

    console.log("CalendarAPI: #syncEvents: Starting sync")

    var queryOpts = this._getQueryOptions(syncTokens)

    let resp = await Q.nfcall(gcal.events.list, queryOpts)
    let data = resp[0]

    console.log("CalendarAPI: #syncEvents: Processing list response")

    // Group items by action
    data.items.forEach((i) => {
      if (i.status == 'cancelled') {
        collector.remove.push(i)
      } else {
        collector.save.push(i)
      }
    })

    console.log(`CalendarAPI: #syncEvents: Response: save.length = ${collector.save.length}, remove.length = ${collector.remove.length}`)

    // Fetch next page of results
    if (data.nextPageToken) {
      console.log("CalendarAPI: #syncEvents: Fetching next page");
      syncTokens.nextPageToken = data.nextPageToken;
      return await this.syncEvents(syncTokens, collector);
    }

    // Finished, so return collector
    if (data.nextSyncToken) {
      console.log("CalendarAPI: #syncEvents: Finished syncing");
      syncTokens.nextSyncToken = data.nextSyncToken;
      delete syncTokens.nextPageToken;
      return {
        syncTokens,
        items: collector
      }
    }
  }
}
<commit_msg>Increase days to sync<commit_after>import Q from 'q'
import google from 'googleapis'
const gcal = google.calendar('v3');

export default class CalendarAPI {

  static get DAYS_TO_SYNC() { return 30 }
  static get MAX_RESULTS() { return 1000 }

  /*
   * Store the auth client to use with api calls
   */

  setAuth(oauth) {
    this.oauth = oauth;
  }

  /*
   * Run the event sync process
   *  If we have a syncToken in storage, initial sync is done, so use it to fetch the changed items
   *  If we have a pageToken in storage, we're in the middle of a sync so grab the next page
   */

  _getQueryOptions(syncTokens) {

    const nextSyncToken = syncTokens.nextSyncToken;
    const nextPageToken = syncTokens.nextPageToken;

    var opts = {
      auth: this.oauth.client,
      calendarId: 'primary',
      maxResults: CalendarAPI.MAX_RESULTS,
      timeZone: 'GMT',
      singleEvents: true
    }

    if (nextSyncToken) {
      opts.syncToken = nextSyncToken;
    } else if (!nextPageToken) {
      var start = new Date();
      start.setHours(0);
      start.setMinutes(0);
      start.setSeconds(0);
      var end = new Date(start);
      end.setDate(end.getDate() + CalendarAPI.DAYS_TO_SYNC);
      opts.timeMin = start.toISOString();
      opts.timeMax = end.toISOString();
    }

    if (nextPageToken) {
      opts.pageToken = nextPageToken;
    }

    return opts;
  }

  async syncEvents(syncTokens, collector={ save: [], remove: [] }) {

    console.log("CalendarAPI: #syncEvents: Starting sync")

    var queryOpts = this._getQueryOptions(syncTokens)

    let resp = await Q.nfcall(gcal.events.list, queryOpts)
    let data = resp[0]

    console.log("CalendarAPI: #syncEvents: Processing list response")

    // Group items by action
    data.items.forEach((i) => {
      if (i.status == 'cancelled') {
        collector.remove.push(i)
      } else {
        collector.save.push(i)
      }
    })

    console.log(`CalendarAPI: #syncEvents: Response: save.length = ${collector.save.length}, remove.length = ${collector.remove.length}`)

    // Fetch next page of results
    if (data.nextPageToken) {
      console.log("CalendarAPI: #syncEvents: Fetching next page");
      syncTokens.nextPageToken = data.nextPageToken;
      return await this.syncEvents(syncTokens, collector);
    }

    // Finished, so return collector
    if (data.nextSyncToken) {
      console.log("CalendarAPI: #syncEvents: Finished syncing");
      syncTokens.nextSyncToken = data.nextSyncToken;
      delete syncTokens.nextPageToken;
      return {
        syncTokens,
        items: collector
      }
    }
  }
}
<|endoftext|>


<commit_before>/*jshint node:true */
/*global describe:false, it:false */

'use strict';

var should = require('chai').should();
var rewire = require('rewire');
var inAdapter = require('../inAdapters/fileAdapter');

describe('inAdapters/fileAdapter/', function() {
	describe('()', function () {
		it('', function (done) {
			done();
		});
	});
});
<commit_msg>Added more unit tests.<commit_after>/*jshint node:true */
/*global describe:false, it:false */

'use strict';

var should = require('chai').should();
var rewire = require('rewire');
var inAdapter = rewire('../inAdapters/fileAdapter');

describe('inAdapters/fileAdapter/', function() {
	inAdapter.__set__('require', function(filename) {
		return {unit: 'test'};
	});

	describe('getRunData()', function () {
		it('should return checksites.json data if exists', function (done) {
			var existsSyncCallCount = 0;
			inAdapter.__set__('fs', {
				existsSync: function(filename) {
					existsSyncCallCount++;
					return true;
				}
			});
			var runData = inAdapter.getRunData();
			existsSyncCallCount.should.equal(1);
			console.log(runData);
			should.exist(runData.unit);
			runData.unit.should.equal('test');
			done();
		});
	});
});
<|endoftext|>


<commit_before>var OrderAction = require("./OrderAction");

function Order(orderParams) {
    if(orderParams.action !== OrderAction.BID && orderParams.action !== OrderAction.ASK) {
        throw new Error("Invalid order action");
    }

    if(orderParams.price == null || isNaN(orderParams.price)) {
        throw new Error("Invalid price");
    }

    if(orderParams.quantity == null || isNaN(orderParams.quantity)) {
        throw new Error("Invalid quantity");
    }

    this.action = orderParams.action;
    this.price = orderParams.price;
    this.quantity = orderParams.quantity;
}

Order.prototype.isBid = function() { return this.action === OrderAction.BID };

Order.prototype.isAsk = function() { return this.action === OrderAction.ASK };

module.exports = Order;<commit_msg>Added canMatch functionality to order object<commit_after>var OrderAction = require("./orderAction");

function Order(orderParams) {
    if(orderParams.action !== OrderAction.BID && orderParams.action !== OrderAction.ASK) {
        throw new Error("Invalid order action");
    }

    if(orderParams.price == null || isNaN(orderParams.price)) {
        throw new Error("Invalid price");
    }

    if(orderParams.quantity == null || isNaN(orderParams.quantity)) {
        throw new Error("Invalid quantity");
    }

    this.action = orderParams.action;
    this.price = orderParams.price;
    this.quantity = orderParams.quantity;
}

Order.prototype.isBid = function() { return this.action === OrderAction.BID };

Order.prototype.isAsk = function() { return this.action === OrderAction.ASK };

Order.prototype.canMatch = function(order) {
    if(this.isBid() === order.isBid()) return false; // can't match two bid/ask orders

    return order.isBid() ? order.price <= this.price : order.price >= this.price;
};

module.exports = Order;<|endoftext|>


<commit_before>const express = require('express');
const app = express();
var path = require('path');

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

app.get('/hello', (request, response) => {
  console.log('called to backend');
  response.send('hello from backend');
});

app.listen(app.get('port'), () => {
  console.log(`chatterbox backend server is running on port: ${app.get('port')}`);
});

if (process.env.NODE_ENV === 'production') {
  console.log("Running in production mode");
  app.use(express.static(path.join(__dirname, 'build')));
}

app.get('/', (request, response) => {
  response.sendFile(path.join(__dirname, 'build', 'index.html'));
});

module.exports = app;<commit_msg>Fixing wrong path to index.html.<commit_after>const express = require('express');
const app = express();
var path = require('path');

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

app.get('/hello', (request, response) => {
  console.log('called to backend');
  response.send('hello from backend');
});

app.listen(app.get('port'), () => {
  console.log(`chatterbox backend server is running on port: ${app.get('port')}`);
});

if (process.env.NODE_ENV === 'production') {
  console.log("Running in production mode");
  app.use(express.static(path.join(__dirname, 'build')));
}

app.get('/', (request, response) => {
  response.sendFile(path.join(__dirname, '../../build', 'index.html'));
});

module.exports = app;<|endoftext|>


<commit_before>var SystemRenderer = require('../SystemRenderer'),
    CanvasMaskManager = require('./utils/CanvasMaskManager'),
    CanvasRenderTarget = require('./utils/CanvasRenderTarget'),
    mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'),
    utils = require('../../utils'),
    CONST = require('../../const');

/**
 * The CanvasRenderer draws the scene and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL.
 * Don't forget to add the CanvasRenderer.view to your DOM or you will not see anything :)
 *
 * @class
 * @memberof PIXI
 * @extends PIXI.SystemRenderer
 * @param [width=800] {number} the width of the canvas view
 * @param [height=600] {number} the height of the canvas view
 * @param [options] {object} The optional renderer parameters
 * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional
 * @param [options.transparent=false] {boolean} If the render view is transparent, default false
 * @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false
 * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment)
 * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2
 * @param [options.clearBeforeRender=true] {boolean} This sets if the CanvasRenderer will clear the canvas or
 *      not before the new render pass.
 * @param [options.roundPixels=false] {boolean} If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation.
 */
function CanvasRenderer(width, height, options)
{
    options = options || {};

    SystemRenderer.call(this, 'Canvas', width, height, options);

    this.type = CONST.RENDERER_TYPE.CANVAS;

    /**
     * The canvas 2d context that everything is drawn with.
     *
     * @member {CanvasRenderingContext2D}
     */
    this.rootContext = this.view.getContext('2d', { alpha: this.transparent });
    this.rootResolution = this.resolution;

    /**
     * Boolean flag controlling canvas refresh.
     *
     * @member {boolean}
     */
    this.refresh = true;

    /**
     * Instance of a CanvasMaskManager, handles masking when using the canvas renderer.
     *
     * @member {PIXI.CanvasMaskManager}
     */
    this.maskManager = new CanvasMaskManager(this);

    /**
     * The canvas property used to set the canvas smoothing property.
     *
     * @member {string}
     */
    this.smoothProperty = 'imageSmoothingEnabled';

    if (!this.rootContext.imageSmoothingEnabled)
    {
        if (this.rootContext.webkitImageSmoothingEnabled)
        {
            this.smoothProperty = 'webkitImageSmoothingEnabled';
        }
        else if (this.rootContext.mozImageSmoothingEnabled)
        {
            this.smoothProperty = 'mozImageSmoothingEnabled';
        }
        else if (this.rootContext.oImageSmoothingEnabled)
        {
            this.smoothProperty = 'oImageSmoothingEnabled';
        }
        else if (this.rootContext.msImageSmoothingEnabled)
        {
            this.smoothProperty = 'msImageSmoothingEnabled';
        }
    }

    this.initPlugins();

    this.blendModes = mapCanvasBlendModesToPixi();
    this._activeBlendMode = null;

    this.context = null;
    this.renderingToScreen = false;

    this.resize(width, height);
}

// constructor
CanvasRenderer.prototype = Object.create(SystemRenderer.prototype);
CanvasRenderer.prototype.constructor =  CanvasRenderer;
module.exports = CanvasRenderer;
utils.pluginTarget.mixin(CanvasRenderer);

/**
 * Renders the object to this canvas view
 *
 * @param displayObject {PIXI.DisplayObject} The object to be rendered
 * @param [renderTexture] {PIXI.RenderTexture} A render texture to be rendered to. If unset, it will render to the root context.
 * @param [clear=false] {boolean} Whether to clear the canvas before drawing
 * @param [transform] {PIXI.Transform} A transformation to be applied
 * @param [skipUpdateTransform=false] {boolean} Whether to skip the update transform
 */
CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform)
{

    if (!this.view){
      return;
    }

     // can be handy to know!
    this.renderingToScreen = !renderTexture;

    this.emit('prerender');

    if(renderTexture)
    {
        renderTexture = renderTexture.baseTexture || renderTexture;

        if(!renderTexture._canvasRenderTarget)
        {

            renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution);
            renderTexture.source = renderTexture._canvasRenderTarget.canvas;
            renderTexture.valid = true;
        }

        this.context = renderTexture._canvasRenderTarget.context;
        this.resolution = renderTexture._canvasRenderTarget.resolution;
    }
    else
    {

        this.context = this.rootContext;
        this.resolution = this.rootResolution;
    }

    var context = this.context;

    this._lastObjectRendered = displayObject;

    if(!skipUpdateTransform)
    {
        // update the scene graph
        var cacheParent = displayObject.parent;
        var tempWt = this._tempDisplayObjectParent.transform.worldTransform;

        if(transform)
        {
            transform.copy(tempWt);
        }
        else
        {
            tempWt.identity();
        }

        displayObject.parent = this._tempDisplayObjectParent;
        displayObject.updateTransform();
        displayObject.parent = cacheParent;
       // displayObject.hitArea = //TODO add a temp hit area
    }

    context.setTransform(1, 0, 0, 1, 0, 0);
    context.globalAlpha = 1;
    context.globalCompositeOperation = this.blendModes[CONST.BLEND_MODES.NORMAL];

    if (navigator.isCocoonJS && this.view.screencanvas)
    {
        context.fillStyle = 'black';
        context.clear();
    }

    if(clear !== undefined ? clear : this.clearBeforeRender)
    {
        if (this.renderingToScreen) {
            if (this.transparent) {
                context.clearRect(0, 0, this.width, this.height);
            }
            else {
                context.fillStyle = this._backgroundColorString;
                context.fillRect(0, 0, this.width, this.height);
            }
        } //else {
            //TODO: implement background for CanvasRenderTarget or RenderTexture?
        //}
    }

    // TODO RENDER TARGET STUFF HERE..
    var tempContext = this.context;

    this.context = context;
    displayObject.renderCanvas(this);
    this.context = tempContext;

    this.emit('postrender');
};

CanvasRenderer.prototype.setBlendMode = function (blendMode)
{
    if(this._activeBlendMode === blendMode) {
      return;
    }

    this.context.globalCompositeOperation = this.blendModes[blendMode];
};

/**
 * Removes everything from the renderer and optionally removes the Canvas DOM element.
 *
 * @param [removeView=false] {boolean} Removes the Canvas element from the DOM.
 */
CanvasRenderer.prototype.destroy = function (removeView)
{
    this.destroyPlugins();

    // call the base destroy
    SystemRenderer.prototype.destroy.call(this, removeView);

    this.context = null;

    this.refresh = true;

    this.maskManager.destroy();
    this.maskManager = null;

    this.smoothProperty = null;
};

/**
 * @extends PIXI.SystemRenderer#resize
 *
 * @param {number} w
 * @param {number} h
 */
CanvasRenderer.prototype.resize = function (w, h)
{
    SystemRenderer.prototype.resize.call(this, w, h);

    //reset the scale mode.. oddly this seems to be reset when the canvas is resized.
    //surely a browser bug?? Let pixi fix that for you..
    if(this.smoothProperty)
    {
        this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR);
    }

};
<commit_msg>fixed canvas render interaction issue<commit_after>var SystemRenderer = require('../SystemRenderer'),
    CanvasMaskManager = require('./utils/CanvasMaskManager'),
    CanvasRenderTarget = require('./utils/CanvasRenderTarget'),
    mapCanvasBlendModesToPixi = require('./utils/mapCanvasBlendModesToPixi'),
    utils = require('../../utils'),
    CONST = require('../../const');

/**
 * The CanvasRenderer draws the scene and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL.
 * Don't forget to add the CanvasRenderer.view to your DOM or you will not see anything :)
 *
 * @class
 * @memberof PIXI
 * @extends PIXI.SystemRenderer
 * @param [width=800] {number} the width of the canvas view
 * @param [height=600] {number} the height of the canvas view
 * @param [options] {object} The optional renderer parameters
 * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional
 * @param [options.transparent=false] {boolean} If the render view is transparent, default false
 * @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false
 * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment)
 * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2
 * @param [options.clearBeforeRender=true] {boolean} This sets if the CanvasRenderer will clear the canvas or
 *      not before the new render pass.
 * @param [options.roundPixels=false] {boolean} If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation.
 */
function CanvasRenderer(width, height, options)
{
    options = options || {};

    SystemRenderer.call(this, 'Canvas', width, height, options);

    this.type = CONST.RENDERER_TYPE.CANVAS;

    /**
     * The canvas 2d context that everything is drawn with.
     *
     * @member {CanvasRenderingContext2D}
     */
    this.rootContext = this.view.getContext('2d', { alpha: this.transparent });
    this.rootResolution = this.resolution;

    /**
     * Boolean flag controlling canvas refresh.
     *
     * @member {boolean}
     */
    this.refresh = true;

    /**
     * Instance of a CanvasMaskManager, handles masking when using the canvas renderer.
     *
     * @member {PIXI.CanvasMaskManager}
     */
    this.maskManager = new CanvasMaskManager(this);

    /**
     * The canvas property used to set the canvas smoothing property.
     *
     * @member {string}
     */
    this.smoothProperty = 'imageSmoothingEnabled';

    if (!this.rootContext.imageSmoothingEnabled)
    {
        if (this.rootContext.webkitImageSmoothingEnabled)
        {
            this.smoothProperty = 'webkitImageSmoothingEnabled';
        }
        else if (this.rootContext.mozImageSmoothingEnabled)
        {
            this.smoothProperty = 'mozImageSmoothingEnabled';
        }
        else if (this.rootContext.oImageSmoothingEnabled)
        {
            this.smoothProperty = 'oImageSmoothingEnabled';
        }
        else if (this.rootContext.msImageSmoothingEnabled)
        {
            this.smoothProperty = 'msImageSmoothingEnabled';
        }
    }

    this.initPlugins();

    this.blendModes = mapCanvasBlendModesToPixi();
    this._activeBlendMode = null;

    this.context = null;
    this.renderingToScreen = false;

    this.resize(width, height);
}

// constructor
CanvasRenderer.prototype = Object.create(SystemRenderer.prototype);
CanvasRenderer.prototype.constructor =  CanvasRenderer;
module.exports = CanvasRenderer;
utils.pluginTarget.mixin(CanvasRenderer);

/**
 * Renders the object to this canvas view
 *
 * @param displayObject {PIXI.DisplayObject} The object to be rendered
 * @param [renderTexture] {PIXI.RenderTexture} A render texture to be rendered to. If unset, it will render to the root context.
 * @param [clear=false] {boolean} Whether to clear the canvas before drawing
 * @param [transform] {PIXI.Transform} A transformation to be applied
 * @param [skipUpdateTransform=false] {boolean} Whether to skip the update transform
 */
CanvasRenderer.prototype.render = function (displayObject, renderTexture, clear, transform, skipUpdateTransform)
{

    if (!this.view){
      return;
    }

     // can be handy to know!
    this.renderingToScreen = !renderTexture;

    this.emit('prerender');

    if(renderTexture)
    {
        renderTexture = renderTexture.baseTexture || renderTexture;

        if(!renderTexture._canvasRenderTarget)
        {

            renderTexture._canvasRenderTarget = new CanvasRenderTarget(renderTexture.width, renderTexture.height, renderTexture.resolution);
            renderTexture.source = renderTexture._canvasRenderTarget.canvas;
            renderTexture.valid = true;
        }

        this.context = renderTexture._canvasRenderTarget.context;
        this.resolution = renderTexture._canvasRenderTarget.resolution;
    }
    else
    {

        this.context = this.rootContext;
        this.resolution = this.rootResolution;
    }

    var context = this.context;

    if(!renderTexture)
    {
        this._lastObjectRendered = displayObject;
    }

    if(!skipUpdateTransform)
    {
        // update the scene graph
        var cacheParent = displayObject.parent;
        var tempWt = this._tempDisplayObjectParent.transform.worldTransform;

        if(transform)
        {
            transform.copy(tempWt);
        }
        else
        {
            tempWt.identity();
        }

        displayObject.parent = this._tempDisplayObjectParent;
        displayObject.updateTransform();
        displayObject.parent = cacheParent;
       // displayObject.hitArea = //TODO add a temp hit area
    }

    context.setTransform(1, 0, 0, 1, 0, 0);
    context.globalAlpha = 1;
    context.globalCompositeOperation = this.blendModes[CONST.BLEND_MODES.NORMAL];

    if (navigator.isCocoonJS && this.view.screencanvas)
    {
        context.fillStyle = 'black';
        context.clear();
    }

    if(clear !== undefined ? clear : this.clearBeforeRender)
    {
        if (this.renderingToScreen) {
            if (this.transparent) {
                context.clearRect(0, 0, this.width, this.height);
            }
            else {
                context.fillStyle = this._backgroundColorString;
                context.fillRect(0, 0, this.width, this.height);
            }
        } //else {
            //TODO: implement background for CanvasRenderTarget or RenderTexture?
        //}
    }

    // TODO RENDER TARGET STUFF HERE..
    var tempContext = this.context;

    this.context = context;
    displayObject.renderCanvas(this);
    this.context = tempContext;

    this.emit('postrender');
};

CanvasRenderer.prototype.setBlendMode = function (blendMode)
{
    if(this._activeBlendMode === blendMode) {
      return;
    }

    this.context.globalCompositeOperation = this.blendModes[blendMode];
};

/**
 * Removes everything from the renderer and optionally removes the Canvas DOM element.
 *
 * @param [removeView=false] {boolean} Removes the Canvas element from the DOM.
 */
CanvasRenderer.prototype.destroy = function (removeView)
{
    this.destroyPlugins();

    // call the base destroy
    SystemRenderer.prototype.destroy.call(this, removeView);

    this.context = null;

    this.refresh = true;

    this.maskManager.destroy();
    this.maskManager = null;

    this.smoothProperty = null;
};

/**
 * @extends PIXI.SystemRenderer#resize
 *
 * @param {number} w
 * @param {number} h
 */
CanvasRenderer.prototype.resize = function (w, h)
{
    SystemRenderer.prototype.resize.call(this, w, h);

    //reset the scale mode.. oddly this seems to be reset when the canvas is resized.
    //surely a browser bug?? Let pixi fix that for you..
    if(this.smoothProperty)
    {
        this.rootContext[this.smoothProperty] = (CONST.SCALE_MODES.DEFAULT === CONST.SCALE_MODES.LINEAR);
    }

};
<|endoftext|>


<commit_before>var isArray = require("x-is-array")
var isObject = require("is-object")

var VPatch = require("./vpatch")
var isVNode = require("./is-vnode")
var isVText = require("./is-vtext")
var isWidget = require("./is-widget")

module.exports = diff

function diff(a, b) {
    var patch = { a: a }
    walk(a, b, patch, 0)
    return patch
}

function walk(a, b, patch, index) {
    if (a === b) {
        hooks(b, patch, index)
        return
    }

    var apply = patch[index]

    if (isWidget(a) || isWidget(b)) {
        // Update/patch a widget
        apply = appendPatch(apply, new VPatch(a, b))
    } else if (isVText(a) && isVText(b)) {
        // Update a text node
        if (a.text !== b.text) {
            apply = appendPatch(apply, new VPatch(a.text, b.text))
        }
    } else if (isVNode(a) && isVNode(b) &&
        a.tagName === b.tagName &&
        a.namespace === b.namespace) {
        // Update a VDOMNode
        var propsPatch = diffProps(a.properties, b.properties, b.hooks)
        if (propsPatch) {
            apply = appendPatch(apply, new VPatch(a.properties, propsPatch))
        }

        apply = diffChildren(a, b, patch, apply, index)
    } else if (a !== b) {
        apply = appendPatch(apply, new VPatch(a, b))

        // We must detect a remove/replace of widgets here so that
        // we can add patch records for any stateful widgets
        if (isVNode(a) && a.hasWidgets &&
            (!isVNode(b) ||
                a.tagName !== b.tagName ||
                a.namespace !== b.namespace)) {
            destroyWidgets(a, patch, index)
        }
    }

    if (apply) {
        patch[index] = apply
    }
}

function diffProps(a, b, hooks) {
    var diff

    for (var aKey in a) {
        if (!(aKey in b)) {
            continue
        }

        var aValue = a[aKey]
        var bValue = b[aKey]

        if (hooks && aKey in hooks) {
            diff = diff || {}
            diff[aKey] = bValue
        } else {
            if (isObject(aValue) && isObject(bValue)) {
                if (getPrototype(bValue) !== getPrototype(aValue)) {
                    diff = diff || {}
                    diff[aKey] = bValue
                } else {
                    var objectDiff = diffProps(aValue, bValue)
                    if (objectDiff) {
                        diff = diff || {}
                        diff[aKey] = objectDiff
                    }
                }
            } else if (aValue !== bValue) {
                diff = diff || {}
                diff[aKey] = bValue
            }
        }
    }

    for (var bKey in b) {
        if (!(bKey in a)) {
            diff = diff || {}
            diff[bKey] = b[bKey]
        }
    }

    return diff
}

function getPrototype(value) {
    if (Object.getPrototypeOf) {
        return Object.getPrototypeOf(value)
    } else if (value.__proto__) {
        return value.__proto__
    } else if (value.constructor) {
        return value.constructor.prototype
    }
}

function diffChildren(a, b, patch, apply, index) {
    var aChildren = a.children
    var bChildren = b.children
    var aLen = aChildren.length
    var bLen = bChildren.length
    var len = aLen < bLen ? aLen : bLen

    for (var i = 0; i < len; i++) {
        var leftNode = aChildren[i]
        var rightNode = bChildren[i]
        index += 1
        walk(leftNode, rightNode, patch, index)

        if (isVNode(leftNode) && leftNode.count) {
            index += leftNode.count
        }
    }

    // Excess nodes in a need to be removed
    for (; i < aLen; i++) {
        var excess = aChildren[i]
        index += 1
        patch[index] = new VPatch(excess, null)
        destroyWidgets(excess, patch, index)

        if (isVNode(excess) && excess.count) {
            index += excess.count
        }
    }

    // Excess nodes in b need to be added
    for (; i < bLen; i++) {
        var addition = bChildren[i]
        apply = appendPatch(apply, new VPatch(null, addition))
    }

    return apply
}

// Patch records for all destroyed widgets must be added because we need
// a DOM node reference for the destroy function
function destroyWidgets(vNode, patch, index) {
    if (isWidget(vNode)) {
        if (typeof vNode.destroy === "function") {
            patch[index] = new VPatch(vNode, null)
        }
    } else if (isVNode(vNode) && vNode.hasWidgets) {
        var children = vNode.children
        var len = children.length
        for (var i = 0; i < len; i++) {
            var child = children[i]
            index += 1

            destroyWidgets(child, patch, index)

            if (isVNode(child) && child.count) {
                index += child.count
            }
        }
    }
}

// Execute hooks when two nodes are identical
function hooks(vNode, patch, index) {
    if (isVNode(vNode)) {
        if (vNode.hooks) {
            patch[index] = new VPatch(vNode.hooks, vNode.hooks)
        }

        if (vNode.descendantHooks) {
            var children = vNode.children
            var len = children.length
            for (var i = 0; i < len; i++) {
                var child = children[i]
                index += 1

                hooks(child, patch, index)

                if (isVNode(child) && child.count) {
                    index += child.count
                }
            }
        }
    }
}

function appendPatch(apply, patch) {
    if (apply) {
        if (isArray(apply)) {
            apply.push(patch)
        } else {
            apply = [apply, patch]
        }

        return apply
    } else {
        return patch
    }
}
<commit_msg>ignore undefined values in diff<commit_after>var isArray = require("x-is-array")
var isObject = require("is-object")

var VPatch = require("./vpatch")
var isVNode = require("./is-vnode")
var isVText = require("./is-vtext")
var isWidget = require("./is-widget")

module.exports = diff

function diff(a, b) {
    var patch = { a: a }
    walk(a, b, patch, 0)
    return patch
}

function walk(a, b, patch, index) {
    if (a === b) {
        hooks(b, patch, index)
        return
    }

    var apply = patch[index]

    if (isWidget(a) || isWidget(b)) {
        // Update/patch a widget
        apply = appendPatch(apply, new VPatch(a, b))
    } else if (isVText(a) && isVText(b)) {
        // Update a text node
        if (a.text !== b.text) {
            apply = appendPatch(apply, new VPatch(a.text, b.text))
        }
    } else if (isVNode(a) && isVNode(b) &&
        a.tagName === b.tagName &&
        a.namespace === b.namespace) {
        // Update a VDOMNode
        var propsPatch = diffProps(a.properties, b.properties, b.hooks)
        if (propsPatch) {
            apply = appendPatch(apply, new VPatch(a.properties, propsPatch))
        }

        apply = diffChildren(a, b, patch, apply, index)
    } else if (a !== b) {
        apply = appendPatch(apply, new VPatch(a, b))

        // We must detect a remove/replace of widgets here so that
        // we can add patch records for any stateful widgets
        if (isVNode(a) && a.hasWidgets &&
            (!isVNode(b) ||
                a.tagName !== b.tagName ||
                a.namespace !== b.namespace)) {
            destroyWidgets(a, patch, index)
        }
    }

    if (apply) {
        patch[index] = apply
    }
}

function diffProps(a, b, hooks) {
    var diff

    for (var aKey in a) {
        if (!(aKey in b)) {
            continue
        }

        var aValue = a[aKey]
        var bValue = b[aKey]

        if (hooks && aKey in hooks) {
            diff = diff || {}
            diff[aKey] = bValue
        } else {
            if (isObject(aValue) && isObject(bValue)) {
                if (getPrototype(bValue) !== getPrototype(aValue)) {
                    diff = diff || {}
                    diff[aKey] = bValue
                } else {
                    var objectDiff = diffProps(aValue, bValue)
                    if (objectDiff) {
                        diff = diff || {}
                        diff[aKey] = objectDiff
                    }
                }
            } else if (aValue !== bValue && bValue !== undefined) {
                diff = diff || {}
                diff[aKey] = bValue
            }
        }
    }

    for (var bKey in b) {
        if (!(bKey in a)) {
            diff = diff || {}
            diff[bKey] = b[bKey]
        }
    }

    return diff
}

function getPrototype(value) {
    if (Object.getPrototypeOf) {
        return Object.getPrototypeOf(value)
    } else if (value.__proto__) {
        return value.__proto__
    } else if (value.constructor) {
        return value.constructor.prototype
    }
}

function diffChildren(a, b, patch, apply, index) {
    var aChildren = a.children
    var bChildren = b.children
    var aLen = aChildren.length
    var bLen = bChildren.length
    var len = aLen < bLen ? aLen : bLen

    for (var i = 0; i < len; i++) {
        var leftNode = aChildren[i]
        var rightNode = bChildren[i]
        index += 1
        walk(leftNode, rightNode, patch, index)

        if (isVNode(leftNode) && leftNode.count) {
            index += leftNode.count
        }
    }

    // Excess nodes in a need to be removed
    for (; i < aLen; i++) {
        var excess = aChildren[i]
        index += 1
        patch[index] = new VPatch(excess, null)
        destroyWidgets(excess, patch, index)

        if (isVNode(excess) && excess.count) {
            index += excess.count
        }
    }

    // Excess nodes in b need to be added
    for (; i < bLen; i++) {
        var addition = bChildren[i]
        apply = appendPatch(apply, new VPatch(null, addition))
    }

    return apply
}

// Patch records for all destroyed widgets must be added because we need
// a DOM node reference for the destroy function
function destroyWidgets(vNode, patch, index) {
    if (isWidget(vNode)) {
        if (typeof vNode.destroy === "function") {
            patch[index] = new VPatch(vNode, null)
        }
    } else if (isVNode(vNode) && vNode.hasWidgets) {
        var children = vNode.children
        var len = children.length
        for (var i = 0; i < len; i++) {
            var child = children[i]
            index += 1

            destroyWidgets(child, patch, index)

            if (isVNode(child) && child.count) {
                index += child.count
            }
        }
    }
}

// Execute hooks when two nodes are identical
function hooks(vNode, patch, index) {
    if (isVNode(vNode)) {
        if (vNode.hooks) {
            patch[index] = new VPatch(vNode.hooks, vNode.hooks)
        }

        if (vNode.descendantHooks) {
            var children = vNode.children
            var len = children.length
            for (var i = 0; i < len; i++) {
                var child = children[i]
                index += 1

                hooks(child, patch, index)

                if (isVNode(child) && child.count) {
                    index += child.count
                }
            }
        }
    }
}

function appendPatch(apply, patch) {
    if (apply) {
        if (isArray(apply)) {
            apply.push(patch)
        } else {
            apply = [apply, patch]
        }

        return apply
    } else {
        return patch
    }
}
<|endoftext|>


<commit_before>FOAModel({
  name: 'DetailView',
  extendsModel: 'AbstractView',

  properties: [
    {
      name:  'value',
      type:  'Value',
      factory: function() { return SimpleValue.create(); },
      postSet: function(oldValue, newValue) {
        if ( oldValue ) oldValue.removeListener(this.onValueChange);
        if ( newValue ) newValue.addListener(this.onValueChange);
        this.onValueChange();
      }
    },
    {
      name:  'model',
      type:  'Model',
      defaultValueFn: function() { return this.value.get().model_; }
    },
    {
      name: 'title',
      defaultValueFn: function() { return "Edit " + this.model.label; }
    },
    {
      name: 'obj',
      getter: function() { return this.value.value; }
    },
    {
      model_: 'BooleanProperty',
      name: 'showActions',
      defaultValue: false,
      postSet: function(old, nu) {
        // TODO: No way to remove the decorator.
        if ( nu ) {
          this.addDecorator(ActionBorder.create());
        }
      }
    },
    {
      model_: 'StringProperty',
      name: 'mode',
      defaultValue: 'read-write'
    }
  ],

  listeners: [
    {
      name: 'onValueChange',
      code: function() {
        if ( ! this.$ ) return;
        this.updateSubViews();
      }
    },
    {
      name: 'onKeyboardShortcut',
      code: function(evt) {
        var action = this.keyMap_[this.evtToKeyCode(evt)];
        if ( action ) action.callIfEnabled(this.obj);
      }
    }
  ],

  methods: {
    bindSubView: function(view, prop) {
      if ( this.get() ) {
        // TODO: setValue is deprecated
        if ( view.setValue ) {
          view.setValue(this.get().propertyValue(prop.name));
        } else {
          view.value = this.get().propertyValue(prop.name);
        }
      }
    },

    viewModel: function() { return this.model; },

    getValue: function() { return this.value; },

    setValue: function (value) {
      if ( this.getValue() ) {
        // todo:
        /// getValue().removeListener(???)
      }
      this.value = value;
      this.updateSubViews();
      // TODO: model this class and make updateSubViews a listener
      // instead of bind()'ing
      value.addListener(this.updateSubViews.bind(this));
    },

    titleHTML: function() {
      var title = this.title;

      return title ?
        '
' + title + '
' :
        '';
    },

    startColumns: function() { return '

'; },
    nextColumn:   function() { return '

'; },
    endColumns:   function() { return '

'; },

    rowToHTML: function(prop, view) {
      var str = "";

      if ( prop.detailViewPreRow ) str += prop.detailViewPreRow(this);

      str += '
';
      if ( view.model_ === DAOController ) {
        str += "
" + prop.label + "
";
        str += view.toHTML();
        str += '	';
      } else {
        str += "" + prop.label + "	";
        str += '';
        str += view.toHTML();
        str += '	';
      }
      str += '
';

      if ( prop.detailViewPostRow ) str += prop.detailViewPostRow(this);

      return str;
    },

    // If the Model supplies a toDetailHTML method, then use it instead.
    toHTML: function() { return (this.model.getPrototype().toDetailHTML || this.defaultToHTML).call(this); },

    defaultToHTML: function() {
      this.children = [];
      var model = this.model;
      var str  = "";

      str += '
';
      str += '
';
      str += this.titleHTML();

      for ( var i = 0 ; i < model.properties.length ; i++ ) {
        var prop = model.properties[i];

        if ( prop.hidden ) continue;

        str += this.rowToHTML(prop, this.createView(prop));
      }

      str += '
';
      str += '
';

      return str;
    },

    initHTML: function() {
      this.SUPER();

      // hooks sub-views upto sub-models
      this.updateSubViews();
      this.initKeyboardShortcuts();
    },

    set: function(obj) {
      this.getValue().set(obj);
    },

    get: function() {
      return this.getValue().get();
    },

    evtToKeyCode: function(evt) {
      var s = '';
      if ( evt.ctrlKey ) s += 'ctrl-';
      if ( evt.shiftKey ) s += 'shift-';
      s += evt.keyCode;
      return s;
    },

    initKeyboardShortcuts: function() {
      var keyMap = {};
      var found = false;
      for ( var i = 0 ; i < this.model.actions.length ; i++ ) {
        var action = this.model.actions[i];
        for ( var j = 0 ; j < action.keyboardShortcuts.length ; j++ ) {
          var key = action.keyboardShortcuts[j];
          var keyCode = key.toString();
          keyMap[keyCode] = action;
          found = true;
        }
      }
      if ( found ) {
        this.keyMap_ = keyMap;
        this.$.parentElement.addEventListener('keydown', this.onKeyboardShortcut);
      }
    },

    updateSubViews: function() {
      var obj = this.get();

      if ( obj === '' ) return;

      for ( var i = 0 ; i < this.children.length ; i++ ) {
        var child = this.children[i];
        var prop  = child.prop;

        if ( ! prop ) continue;

        try {
          if ( child.model_.DATA ) child.data = obj;
          else child.value = obj.propertyValue(prop.name);
        } catch (x) {
          console.log("error: ", prop.name, " ", x);
        }
      }
    },

    setModel: function(obj) {
      if ( ! obj ) return;

      this.obj = obj;
    },

    destroy: function()
    {
    }
  }
});
<commit_msg>DetailView now supports DetailView's ability to change model.<commit_after>FOAModel({
  name: 'DetailView',
  extendsModel: 'AbstractView',

  properties: [
    {
      name:  'value',
      type:  'Value',
      factory: function() { return SimpleValue.create(); },
      postSet: function(oldValue, newValue) {
        if ( oldValue ) oldValue.removeListener(this.onValueChange);
        if ( newValue ) newValue.addListener(this.onValueChange);
        this.onValueChange();
      }
    },
    {
      name:  'model',
      type:  'Model',
      postSet: function(_, m) {
        if ( this.$ ) {
          this.children = [];
          this.$.outerHTML = this.toHTML();
          this.initHTML();
        }
      }
    },
    {
      name: 'title',
      defaultValueFn: function() { return "Edit " + this.model.label; }
    },
    {
      name: 'obj',
      getter: function() { return this.value.value; }
    },
    {
      model_: 'BooleanProperty',
      name: 'showActions',
      defaultValue: false,
      postSet: function(old, nu) {
        // TODO: No way to remove the decorator.
        if ( nu ) {
          this.addDecorator(ActionBorder.create());
        }
      }
    },
    {
      model_: 'StringProperty',
      name: 'mode',
      defaultValue: 'read-write'
    }
  ],

  listeners: [
    {
      name: 'onValueChange',
      code: function() {
        if ( this.obj && this.obj.model_ ) this.model = this.obj.model_;
        if ( this.$ ) this.updateSubViews();
      }
    },
    {
      name: 'onKeyboardShortcut',
      code: function(evt) {
        var action = this.keyMap_[this.evtToKeyCode(evt)];
        if ( action ) action.callIfEnabled(this.obj);
      }
    }
  ],

  methods: {
    bindSubView: function(view, prop) {
      if ( this.get() ) {
        // TODO: setValue is deprecated
        if ( view.setValue ) {
          view.setValue(this.get().propertyValue(prop.name));
        } else {
          view.value = this.get().propertyValue(prop.name);
        }
      }
    },

    viewModel: function() { return this.model; },

    getValue: function() { return this.value; },

    setValue: function (value) {
      if ( this.getValue() ) {
        // todo:
        /// getValue().removeListener(???)
      }
      this.value = value;
      this.updateSubViews();
      // TODO: model this class and make updateSubViews a listener
      // instead of bind()'ing
      value.addListener(this.updateSubViews.bind(this));
    },

    titleHTML: function() {
      var title = this.title;

      return title ?
        '
' + title + '
' :
        '';
    },

    startColumns: function() { return '

'; },
    nextColumn:   function() { return '

'; },
    endColumns:   function() { return '

'; },

    rowToHTML: function(prop, view) {
      var str = "";

      if ( prop.detailViewPreRow ) str += prop.detailViewPreRow(this);

      str += '
';
      if ( view.model_ === DAOController ) {
        str += "
" + prop.label + "
";
        str += view.toHTML();
        str += '	';
      } else {
        str += "" + prop.label + "	";
        str += '';
        str += view.toHTML();
        str += '	';
      }
      str += '
';

      if ( prop.detailViewPostRow ) str += prop.detailViewPostRow(this);

      return str;
    },

    // If the Model supplies a toDetailHTML method, then use it instead.
    toHTML: function() { return (this.model.getPrototype().toDetailHTML || this.defaultToHTML).call(this); },

    defaultToHTML: function() {
      this.children = [];
      var model = this.model;
      var str  = "";

      str += '
';
      str += '
';
      str += this.titleHTML();

      for ( var i = 0 ; i < model.properties.length ; i++ ) {
        var prop = model.properties[i];

        if ( prop.hidden ) continue;

        str += this.rowToHTML(prop, this.createView(prop));
      }

      str += '
';
      str += '
';

      return str;
    },

    initHTML: function() {
      this.SUPER();

      // hooks sub-views upto sub-models
      this.updateSubViews();
      this.initKeyboardShortcuts();
    },

    set: function(obj) {
      this.getValue().set(obj);
    },

    get: function() {
      return this.getValue().get();
    },

    evtToKeyCode: function(evt) {
      var s = '';
      if ( evt.ctrlKey ) s += 'ctrl-';
      if ( evt.shiftKey ) s += 'shift-';
      s += evt.keyCode;
      return s;
    },

    initKeyboardShortcuts: function() {
      var keyMap = {};
      var found = false;
      for ( var i = 0 ; i < this.model.actions.length ; i++ ) {
        var action = this.model.actions[i];
        for ( var j = 0 ; j < action.keyboardShortcuts.length ; j++ ) {
          var key = action.keyboardShortcuts[j];
          var keyCode = key.toString();
          keyMap[keyCode] = action;
          found = true;
        }
      }
      if ( found ) {
        this.keyMap_ = keyMap;
        this.$.parentElement.addEventListener('keydown', this.onKeyboardShortcut);
      }
    },

    updateSubViews: function() {
      var obj = this.get();

      if ( obj === '' ) return;

      for ( var i = 0 ; i < this.children.length ; i++ ) {
        var child = this.children[i];
        var prop  = child.prop;

        if ( ! prop ) continue;

        try {
          if ( child.model_.DATA ) child.data = obj;
          else child.value = obj.propertyValue(prop.name);
        } catch (x) {
          console.log("error: ", prop.name, " ", x);
        }
      }
    },

    setModel: function(obj) {
      if ( ! obj ) return;

      this.obj = obj;
    }
  }
});
<|endoftext|>


<commit_before>// We have to make sure some client-side dependencies
// actually exist in node_modules.

var _ = require('underscore'),
    exec = require('child_process').exec;

// TODO: Don't duplicate; pull from assetCompiler.
var dependencies = [
  'underscore',
  'backbone',
  'async',
  'node-polyglot'
];

var root = __dirname + '/..';

_.each(dependencies, function(dep) {
  exec('cd ' + root + '; npm link ' + dep);
  console.log('POSTINSTALL: Linking dependency "'+dep+'".');
});
<commit_msg>adding handlebars dep<commit_after>// We have to make sure some client-side dependencies
// actually exist in node_modules.

var _ = require('underscore'),
    exec = require('child_process').exec;

// TODO: Don't duplicate; pull from assetCompiler.
var dependencies = [
  'underscore',
  'backbone',
  'async',
  'node-polyglot',
  'handlebars'
];

var root = __dirname + '/..';

_.each(dependencies, function(dep) {
  exec('cd ' + root + '; npm link ' + dep);
  console.log('POSTINSTALL: Linking dependency "'+dep+'".');
});
<|endoftext|>


<commit_before>/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/* eslint-env node, mocha */
/* global $dbConfig */
import { jsdom } from 'jsdom';

import expect from '../../../test-helpers/expect';
import initBookshelf from '../../../src/api/db';
import { login } from '../../../test-helpers/api';

let bookshelf = initBookshelf($dbConfig);
let User = bookshelf.model('User');

describe('ListPage', () => {
  it('anonymous can not open /', async () => {
    await expect('/', 'to redirect');
  });

  describe('when user is logged in', () => {
    let user;
    let sessionId;

    beforeEach(async () => {
      await bookshelf.knex('users').del();
      user = await User.create('test', 'test', 'test@example.com');

      sessionId = await login('test', 'test');
    });

    afterEach(async () => {
      await user.destroy();
    });

    it('user can open / and see posting form', async () => {
      let context = await expect({ url: '/', session: sessionId }, 'to open successfully');

      let document = jsdom(context.httpResponse.body);

      let pageContent = await expect(document.body, 'queried for first', '#content>.page .page__content');
      await expect(pageContent, 'to have child', '.box-post');  // posting form

      let postsContainer = pageContent.childNodes[1];
      await expect(postsContainer, 'to have no children');
    });
  });
});
<commit_msg>test which shows broken server rendering<commit_after>/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/* eslint-env node, mocha */
/* global $dbConfig */
import { jsdom } from 'jsdom';
import { v4 as uuid4 } from 'uuid';

import expect from '../../../test-helpers/expect';
import initBookshelf from '../../../src/api/db';
import { login } from '../../../test-helpers/api';

let bookshelf = initBookshelf($dbConfig);
let Post = bookshelf.model('Post');
let User = bookshelf.model('User');

describe('ListPage', () => {
  it('anonymous can not open /', async () => {
    await expect('/', 'to redirect');
  });

  describe('when user is logged in', () => {
    let user;
    let sessionId;

    beforeEach(async () => {
      await bookshelf.knex('users').del();
      user = await User.create('test', 'test', 'test@example.com');

      sessionId = await login('test', 'test');
    });

    afterEach(async () => {
      await user.destroy();
    });

    it('user can open / and see posting form', async () => {
      let context = await expect({ url: '/', session: sessionId }, 'to open successfully');

      let document = jsdom(context.httpResponse.body);

      let pageContent = await expect(document.body, 'queried for first', '#content>.page .page__content');
      await expect(pageContent, 'to have child', '.box-post');  // posting form

      let postsContainer = pageContent.childNodes[1];
      await expect(postsContainer, 'to have no children');
    });

    describe('when user made a post', () => {
      let post;

      beforeEach(async () => {
        // FIXME: extract code from controller into model and reuse here
        post = new Post({
          id: uuid4(),
          type: 'short_text',
          user_id: user.get('id'),
          text: 'Lorem ipsum'
        });
        await post.save(null, {method: 'insert'});
      });

      afterEach(async () => {
        await post.destroy();
      });

      it('user can open / and see 1 post there', async () => {
        let context = await expect({ url: '/', session: sessionId }, 'to open successfully');

        let document = jsdom(context.httpResponse.body);

        let pageContent = await expect(document.body, 'queried for first', '#content>.page .page__content');
        await expect(pageContent, 'to have child', '.box-post');  // posting form

        let postsContainer = pageContent.childNodes[1];
        await expect(postsContainer, 'to have children');
      });
    });
  });
});
<|endoftext|>