<commit_before>/**
 * Server for testing Mobify.js!
 */
var http = require('http');
var express = require('express');
var fs = require('fs');
var path = require('path');
var Url = require('url');
var hbs = require('hbs');

http.globalAgent.maxSockets = 100;

/**
 * Inlines the V7 Tag on test fixtures.
 */
var inlineTag = function(req, res) {
    var page = fs.readFileSync(__dirname + req.path, 'utf8');
    var tag = fs.readFileSync(__dirname + "/tag/v7.js", 'utf8');

    page = page.replace("<script src=\"/tag/v7.js\"></script>", "<script>" + tag + "</script>");

    res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8', 'Cache-Control': 'no-cache'});
    res.end(page);
};

/**
 * Used for test "capture captures the complete document" in `tests/capture.html`.
 */
var slowResponse = function(req, res) {
    var split = fs.readFileSync(__dirname + req.path, 'utf8').split('<!-- SPLIT -->')
    res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
    res.write(split[0]);
    var chunk = 1;
    var iid = setInterval(function() {
        res.write(split[chunk]);
        chunk++;
        if (chunk === split.length){
            clearInterval(iid);
            res.end();
        }
    }, 500);
}

/**
 * Used for test "capture captures the complete document" in `tests/capture.html`.
 */
var cachedResponse = function(req, res, next) {
    res.header('Content-Type', 'application/javascript');
    res.header('Cache-Control', 'max-age=10000');
    next();
}

/**
 * Browser entry point for Jazzcat Performance tests.
 */
var jazzcatPerformanceIndex = function(req, res) {
    res.render('jazzcat', {});
};

/**
 * Main code for jazzcat runners. Passed in as a context variable for the
 * bootstrap tag using toString.
 */
var jazzcatMainExec = function(){
    var capturing = window.Mobify && window.Mobify.capturing || false;
    Jazzcat.httpCache.save = function() {
        return console.log("mocking save to do nothing");
    }
    if (capturing) {
        // Initiate capture
        Mobify.Capture.init(function(capture){

            // Grab reference to a newly created document
            var capturedDoc = capture.capturedDoc;

            var matchType = location.href.match(/responseType=([^&;]*)/);
            var responseType = (matchType && matchType[1]) || 'jsonp';

            var matchConcat = location.href.match(/concat=([^&;]*)/);
            var concat = (matchConcat && matchConcat[1] === 'true');
            if (concat === null) {
                concat = true;
            }

            // Grab all scripts to be concatenated into one request
            if (!/disableJazzcat=1/.test(location.href)) {
                var scripts = capturedDoc.querySelectorAll('script');
                Mobify.Jazzcat.optimizeScripts(scripts, {
                    responseType: responseType,
                    base: '',
                    concat: concat
                });
            }

            // Render source DOM to document
            capture.renderCapturedDoc();
        });
    }
};

/**
 * Page that runs the Jazzcat performance test.
 */
var jazzcatPerformanceRunner = function(req, res) {
    var numScripts = parseInt(req.params.numScripts);
    var scripts = [];

    for (var i = 0; i < numScripts; i++) {
        var index = i % files.length;
        scripts.push(resourcesUrl + scriptsArray[index].fileName + "?" + i);
    }

    // Append timestamp in order to ensure the mobify.js does not always
    // get loaded cached, and also ensures the second load of mobify.js
    // on a test does not load again.
    var library = '/build/mobify.min.js';
    //var library = '/build/mobify.js'; // uncomment for debugging
    library += "?" + new Date().getTime();

    res.header('Connection', 'close');

    res.render('fixtures/jazzcatRunner', {
        library: library,
        main: jazzcatMainExec.toString(),
        scripts: scripts
    });
};

/**
 * Implements the Jazzcat JSONP API.
 */
var jazzcatJsonp = function(req, res) {
    var scripts = JSON.parse(req.params.scripts);
    var scriptData = scripts.map(function(script){
        var pathname = Url.parse(script).pathname;
        return {
            url: script,
            data: JSON.stringify(scriptsObj[pathname])
        }
    });

    res.header('Content-Type', 'application/javascript')
    res.render('fixtures/jazzcatJSONResponse', {scripts: scriptData});
};

/**
 * Implements the Jazzcat JS API.
 */
var jazzcatJs = function(req, res) {

    var scripts = JSON.parse(req.params.scripts);
    var scriptData = scripts.map(function(script){
        var pathname = Url.parse(script).pathname;
        return scriptsObj[pathname].toString()
    });

    res.header('Content-Type', 'application/javascript')
    res.render('fixtures/jazzcatJSResponse', {scripts: scriptData})
};

// Load scripts for the mock mock Jazzcat API.
var resourcesUrl = '/mobifyjs/performance/resources/samplescripts/';
var files = fs.readdirSync(__dirname + resourcesUrl).filter(function(folder) {
    return folder[0] !== '.';
});

var scriptsObj = {};
var scriptsArray = [];

for (file in files) {
    var fileName = files[file];
    var fileData = fs.readFileSync(__dirname + resourcesUrl + files[file], 'utf8');
    scriptsArray.push({fileName: fileName, fileData: fileData});
    scriptsObj[resourcesUrl + fileName] = fileData;
}

hbs.registerPartial('bootstrap', fs.readFileSync(__dirname + '/tag/bootstrap.html', 'utf8'));

/**
 * Image resizing error test cases
 */

var textMime = function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello, World');
};

var emptyResponse = function(req, res) {
    res.setHeader('Content-Type', 'image/jpeg');
    res.end();
};

var imageData = fs.readFileSync(path.normalize('./examples/assets/images/grumpycat.jpg'));

var wrongMime = function(req, res) {
    res.setHeader('Content-Type', 'image/png');
    res.end(imageData);
};

var partialImage = function(bytes) {
    return function(req, res) {
        res.setHeader('Content-Type', 'image/jpeg');
        res.end(imageData.slice(0, bytes));
    };
};

var abortedImage = function(req, res) {
    res.setHeader('Content-Type', 'image/jpeg');
    res.write(imageData.slice(0, 1024));
    res.socket.destroy();
};

var notFound = function(req, res) {
    res.statusCode = 404;
    res.setHeader('Cotnent-Type', 'text/plain');
    res.end('Not Found!');
};

var serverError = function(req, res) {
    res.statusCode = 500;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Faux Internal Server Error');
};

var fakeJPEG = function(req, res) {
    res.setHeader('Content-Type', 'image/jpeg');
    res.end('asdf');
};

var app = express();

app.set('views', __dirname + '/performance');
app.set('view engine', 'html');
app.engine('html', require('hbs').__express);

app.use(function(req, res, next) {
    res.header('Cache-Control' , 'max-age=0, no-cache, no-store');
    next();
});

app.get('/build/mobify(.min)?.js', cachedResponse);
app.get('/tests/fixtures/split*', slowResponse);
app.get('/tests/fixtures/tag/*', inlineTag);
app.get('/performance/jazzcat/', jazzcatPerformanceIndex);
app.get('/performance/jazzcat/runner/:numScripts', jazzcatPerformanceRunner);

app.get('/jsonp/Jazzcat.load/:scripts', jazzcatJsonp);
app.get('/js/:scripts', jazzcatJs);

app.get('/imagetests/textmime', textMime);
app.get('/imagetests/emptyresponse', emptyResponse);
app.get('/imagetests/wrongmime', wrongMime);
app.get('/imagetests/partialimage100b', partialImage(100));
app.get('/imagetests/partialimage1k', partialImage(1024));
app.get('/imagetests/abortedimage', abortedImage);
app.get('/imagetests/notFound', notFound);
app.get('/imagetests/serverError', serverError);
app.get('/imagetests/fakejpeg', fakeJPEG);

if (require.main === module) {
    app.use(express.static(__dirname));
    app.listen(process.env.PORT || 3000);
}

module.exports = app;
<commit_msg>Fixes problem with 404s<commit_after>/**
 * Server for testing Mobify.js!
 */
var http = require('http');
var express = require('express');
var fs = require('fs');
var path = require('path');
var Url = require('url');
var hbs = require('hbs');

http.globalAgent.maxSockets = 100;

/**
 * Inlines the V7 Tag on test fixtures.
 */
var inlineTag = function(req, res, next) {
    try {
        var page = fs.readFileSync(__dirname + req.path, 'utf8');
    } catch (e) {
        return next();
    }
    var tag = fs.readFileSync(__dirname + "/tag/v7.js", 'utf8');

    page = page.replace("<script src=\"/tag/v7.js\"></script>", "<script>" + tag + "</script>");

    res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8', 'Cache-Control': 'no-cache'});
    res.end(page);
};

/**
 * Used for test "capture captures the complete document" in `tests/capture.html`.
 */
var slowResponse = function(req, res) {
    var split = fs.readFileSync(__dirname + req.path, 'utf8').split('<!-- SPLIT -->')
    res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
    res.write(split[0]);
    var chunk = 1;
    var iid = setInterval(function() {
        res.write(split[chunk]);
        chunk++;
        if (chunk === split.length){
            clearInterval(iid);
            res.end();
        }
    }, 500);
}

/**
 * Used for test "capture captures the complete document" in `tests/capture.html`.
 */
var cachedResponse = function(req, res, next) {
    res.header('Content-Type', 'application/javascript');
    res.header('Cache-Control', 'max-age=10000');
    next();
}

/**
 * Browser entry point for Jazzcat Performance tests.
 */
var jazzcatPerformanceIndex = function(req, res) {
    res.render('jazzcat', {});
};

/**
 * Main code for jazzcat runners. Passed in as a context variable for the
 * bootstrap tag using toString.
 */
var jazzcatMainExec = function(){
    var capturing = window.Mobify && window.Mobify.capturing || false;
    Jazzcat.httpCache.save = function() {
        return console.log("mocking save to do nothing");
    }
    if (capturing) {
        // Initiate capture
        Mobify.Capture.init(function(capture){

            // Grab reference to a newly created document
            var capturedDoc = capture.capturedDoc;

            var matchType = location.href.match(/responseType=([^&;]*)/);
            var responseType = (matchType && matchType[1]) || 'jsonp';

            var matchConcat = location.href.match(/concat=([^&;]*)/);
            var concat = (matchConcat && matchConcat[1] === 'true');
            if (concat === null) {
                concat = true;
            }

            // Grab all scripts to be concatenated into one request
            if (!/disableJazzcat=1/.test(location.href)) {
                var scripts = capturedDoc.querySelectorAll('script');
                Mobify.Jazzcat.optimizeScripts(scripts, {
                    responseType: responseType,
                    base: '',
                    concat: concat
                });
            }

            // Render source DOM to document
            capture.renderCapturedDoc();
        });
    }
};

/**
 * Page that runs the Jazzcat performance test.
 */
var jazzcatPerformanceRunner = function(req, res) {
    var numScripts = parseInt(req.params.numScripts);
    var scripts = [];

    for (var i = 0; i < numScripts; i++) {
        var index = i % files.length;
        scripts.push(resourcesUrl + scriptsArray[index].fileName + "?" + i);
    }

    // Append timestamp in order to ensure the mobify.js does not always
    // get loaded cached, and also ensures the second load of mobify.js
    // on a test does not load again.
    var library = '/build/mobify.min.js';
    //var library = '/build/mobify.js'; // uncomment for debugging
    library += "?" + new Date().getTime();

    res.header('Connection', 'close');

    res.render('fixtures/jazzcatRunner', {
        library: library,
        main: jazzcatMainExec.toString(),
        scripts: scripts
    });
};

/**
 * Implements the Jazzcat JSONP API.
 */
var jazzcatJsonp = function(req, res) {
    var scripts = JSON.parse(req.params.scripts);
    var scriptData = scripts.map(function(script){
        var pathname = Url.parse(script).pathname;
        return {
            url: script,
            data: JSON.stringify(scriptsObj[pathname])
        }
    });

    res.header('Content-Type', 'application/javascript')
    res.render('fixtures/jazzcatJSONResponse', {scripts: scriptData});
};

/**
 * Implements the Jazzcat JS API.
 */
var jazzcatJs = function(req, res) {

    var scripts = JSON.parse(req.params.scripts);
    var scriptData = scripts.map(function(script){
        var pathname = Url.parse(script).pathname;
        return scriptsObj[pathname].toString()
    });

    res.header('Content-Type', 'application/javascript')
    res.render('fixtures/jazzcatJSResponse', {scripts: scriptData})
};

// Load scripts for the mock mock Jazzcat API.
var resourcesUrl = '/mobifyjs/performance/resources/samplescripts/';
var files = fs.readdirSync(__dirname + resourcesUrl).filter(function(folder) {
    return folder[0] !== '.';
});

var scriptsObj = {};
var scriptsArray = [];

for (file in files) {
    var fileName = files[file];
    var fileData = fs.readFileSync(__dirname + resourcesUrl + files[file], 'utf8');
    scriptsArray.push({fileName: fileName, fileData: fileData});
    scriptsObj[resourcesUrl + fileName] = fileData;
}

hbs.registerPartial('bootstrap', fs.readFileSync(__dirname + '/tag/bootstrap.html', 'utf8'));

/**
 * Image resizing error test cases
 */

var textMime = function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello, World');
};

var emptyResponse = function(req, res) {
    res.setHeader('Content-Type', 'image/jpeg');
    res.end();
};

var imageData = fs.readFileSync(path.normalize('./examples/assets/images/grumpycat.jpg'));

var wrongMime = function(req, res) {
    res.setHeader('Content-Type', 'image/png');
    res.end(imageData);
};

var partialImage = function(bytes) {
    return function(req, res) {
        res.setHeader('Content-Type', 'image/jpeg');
        res.end(imageData.slice(0, bytes));
    };
};

var abortedImage = function(req, res) {
    res.setHeader('Content-Type', 'image/jpeg');
    res.write(imageData.slice(0, 1024));
    res.socket.destroy();
};

var notFound = function(req, res) {
    res.statusCode = 404;
    res.setHeader('Cotnent-Type', 'text/plain');
    res.end('Not Found!');
};

var serverError = function(req, res) {
    res.statusCode = 500;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Faux Internal Server Error');
};

var fakeJPEG = function(req, res) {
    res.setHeader('Content-Type', 'image/jpeg');
    res.end('asdf');
};

var app = express();

app.set('views', __dirname + '/performance');
app.set('view engine', 'html');
app.engine('html', require('hbs').__express);

app.use(function(req, res, next) {
    res.header('Cache-Control' , 'max-age=0, no-cache, no-store');
    next();
});

app.get('/build/mobify(.min)?.js', cachedResponse);
app.get('/tests/fixtures/split*', slowResponse);
app.get('/tests/fixtures/tag/*', inlineTag);
app.get('/performance/jazzcat/', jazzcatPerformanceIndex);
app.get('/performance/jazzcat/runner/:numScripts', jazzcatPerformanceRunner);

app.get('/jsonp/Jazzcat.load/:scripts', jazzcatJsonp);
app.get('/js/:scripts', jazzcatJs);

app.get('/imagetests/textmime', textMime);
app.get('/imagetests/emptyresponse', emptyResponse);
app.get('/imagetests/wrongmime', wrongMime);
app.get('/imagetests/partialimage100b', partialImage(100));
app.get('/imagetests/partialimage1k', partialImage(1024));
app.get('/imagetests/abortedimage', abortedImage);
app.get('/imagetests/notFound', notFound);
app.get('/imagetests/serverError', serverError);
app.get('/imagetests/fakejpeg', fakeJPEG);

if (require.main === module) {
    app.use(express.static(__dirname));
    app.listen(process.env.PORT || 3000);
}

module.exports = app;
<|endoftext|>


<commit_before>var run = require('child_process').exec,
    path = require('path'),
    ncp = require('ncp').ncp,
    colors = require('colors');

var _deploy = function(name){

  // check to see if heroku is installed
  run('which heroku', function(err, out, stderr){
    if (err) {
      console.log("You need to install heroku first. Here's the download page".red)
      setTimeout(function(){ require('open')('https://toolbelt.heroku.com/') }, 700)
    } else {

      // check if there is already a heroku app
      run("git branch -r | grep heroku", function(err,out,stdout){
        if (err) {

          // these all need to be run as a sequence
          var source = path.join(__dirname, '../../templates/heroku');
          var destination = path.normalize(process.cwd());

          ncp(source, destination, function (err) {
            if (err) { return console.error(err); }
            console.log('heroku config files copied...'.grey);
          });

          run("git add Procfile package.json server.js; git commit -am 'heroku config'", function(err){
            if (err) { return console.error(err) }
            console.log('comitting heroku config files to git...');
          });

          console.log('creating app on heroku...'.grey);
          if (name == undefined) { name = "" } else { name = name[0] }

          // if not, create a new app and deploy
          // run('heroku create ' + name, function(err, out, stderr){
          //   if (err) { return console.error(err) }
          //   console.log('new heroku app created'.green);
          //   // output the heroku output?
          // });
        } else {

          // if there already is an app, deploy it
          // run("git rev-parse --abbrev-ref HEAD", function(err, out, stdout){
          //   run('git push heroku ' + out, function(err, out, stderr){
          //     if (err) {
          //       console.log('error: '.red + err);
          //     } else {
          //       // need to parse the output to grab the url here if possible
          //       console.log('successfully deployed to heroku'.green);
          //     }
          //   });
          // });
        }
      })
    }
  });

}

module.exports = { execute: _deploy, needs_config: true }<commit_msg>heroku config<commit_after>var run = require('child_process').exec,
    path = require('path'),
    ncp = require('ncp').ncp,
    colors = require('colors');

var _deploy = function(name){

  // check to see if heroku is installed
  run('which heroku', function(err, out, stderr){
    if (err) {
      console.log("You need to install heroku first. Here's the download page".red)
      setTimeout(function(){ require('open')('https://toolbelt.heroku.com/') }, 700)
    } else {

      // check if there is already a heroku app
      run("git branch -r | grep heroku", function(err,out,stdout){
        if (err) {

          // these all need to be run as a sequence
          var source = path.join(__dirname, '../../templates/heroku');
          var destination = path.normalize(process.cwd());

          ncp(source, destination, function (err) {
            if (err) { return console.error(err); }
            console.log('heroku config files copied...'.grey);
          });

          run("git add Procfile package.json server.js; git commit -am 'heroku config'", function(err){
            if (err) { return console.error(err) }
            console.log('comitting heroku config files to git...'.grey);
          });

          console.log('creating app on heroku...'.grey);
          if (name == undefined) { name = "" } else { name = name[0] }

          // if not, create a new app and deploy
          // run('heroku create ' + name, function(err, out, stderr){
          //   if (err) { return console.error(err) }
          //   console.log('new heroku app created'.green);
          //   // output the heroku output?
          // });
        } else {

          // if there already is an app, deploy it
          // run("git rev-parse --abbrev-ref HEAD", function(err, out, stdout){
          //   run('git push heroku ' + out, function(err, out, stderr){
          //     if (err) {
          //       console.log('error: '.red + err);
          //     } else {
          //       // need to parse the output to grab the url here if possible
          //       console.log('successfully deployed to heroku'.green);
          //     }
          //   });
          // });
        }
      })
    }
  });

}

module.exports = { execute: _deploy, needs_config: true }<|endoftext|>


<commit_before>function setTime(hours) {
	updateClock(hours);
}

function changeStocks() {
	$('#stocks_modal').modal('show');
}

// make stocks editable
window.onload = function () {
	$('.s_edit').click(function(event){

		if ($(this).hasClass('fa-pencil')) {
			// edit
			$(this).removeClass('fa-pencil');
			$(this).addClass('fa-save');
			var elem = $(this).closest('.portlet').children('h3')[0];

			var text = elem.innerHTML;
			$(elem).replaceWith("<input type='edit' value='" + text + "'>");

		} else {
			// save
			$(this).removeClass('fa-save');
			$(this).addClass('fa-pencil');
			var elem = $(this).closest('.portlet').children('input')[0];

			var text = $(elem).val();
			$(elem).replaceWith('
' + text + '
');
		}
	});
}

function saveStocks() {
	var elems = document.querySelectorAll('.column2 .portlet h3')
	var stocks = [];

	for (var i = 0; i < 4; i++) {
		stocks.push(elems[i].innerHTML);
	}

	data['stocks'] = stocks;
	sendData(data);
}

function resetStocks() {
	var stocks = data['stocks'];
	var elems = document.querySelectorAll('.column2 .portlet');

	for (var i = 0; i < 4; i++) {
		var elem = elems[i].children[1];
		var text = data['stocks'][i];
		$(elem).replaceWith('
' + text + '
');
	};
}

function getModOrder() {
	var elems = document.querySelectorAll('.column .portlet .mod');
	var modOrder = [];

	for (var i = 0; i < elems.length; i++) {
		modOrder.push(elems[i].id);
	};

	data['modOrder'] = modOrder;
}<commit_msg>update so that it saves the stocks even if you forgot to do them individually<commit_after>function setTime(hours) {
	updateClock(hours);
}

function changeStocks() {
	$('#stocks_modal').modal('show');
}

// make stocks editable
window.onload = function () {
	$('.s_edit').click(function(event){

		if ($(this).hasClass('fa-pencil')) {
			// edit
			$(this).removeClass('fa-pencil');
			$(this).addClass('fa-save');
			var elem = $(this).closest('.portlet').children('h3')[0];

			var text = elem.innerHTML;
			$(elem).replaceWith("<input type='edit' value='" + text + "'>");

		} else {
			// save
			$(this).removeClass('fa-save');
			$(this).addClass('fa-pencil');
			var elem = $(this).closest('.portlet').children('input')[0];

			var text = $(elem).val();
			$(elem).replaceWith('
' + text + '
');
		}
	});
}

function lockStocks() {
	var elems = document.getElementsByClassName('s_edit');

	for (var i = 0; i < elems.length; i++) {
		console.log(elems[i]);
		if ($(elems[i]).hasClass('fa-pencil')) {
			// do nothing
			continue;
		} else {
			// otherwise lock what they have in there and save it
			$(elems[i]).removeClass('fa-save');
			$(elems[i]).addClass('fa-pencil');
			var elem = $(elems[i]).closest('.portlet').children('input')[0];

			var text = $(elem).val();
			$(elem).replaceWith('
' + text + '
');
		}
	};
}

function saveStocks() {
	lockStocks();

	var elems = document.querySelectorAll('.column2 .portlet h3')
	var stocks = [];

	for (var i = 0; i < 4; i++) {
		stocks.push(elems[i].innerHTML);
	}

	data['stocks'] = stocks;
	sendData(data);
}

function resetStocks() {
	var stocks = data['stocks'];
	var elems = document.querySelectorAll('.column2 .portlet');

	for (var i = 0; i < 4; i++) {
		var elem = elems[i].children[1];
		var text = data['stocks'][i];
		$(elem).replaceWith('
' + text + '
');
	};
}

function getModOrder() {
	var elems = document.querySelectorAll('.column .portlet .mod');
	var modOrder = [];

	for (var i = 0; i < elems.length; i++) {
		modOrder.push(elems[i].id);
	};

	data['modOrder'] = modOrder;
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Groupon, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 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.
 *
 * Neither the name of GROUPON nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * 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
 * HOLDER 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.
 */

'use strict';

const fs = require('fs');

const path = require('path');

const semver = require('semver');

const addLicenseHeaders = require('../license');

const verifyClean = require('../git/verify-clean');

const ensureTag = require('../git/ensure-tag');

const determineReleaseInfo = require('../steps/release-info');

const tagPullRequest = require('../steps/tag-pr');

const getPendingChanges = require('../steps/pending-changes');

const detectBranch = require('../steps/detect-branch');

function verifyLicenseHeaders(cwd, pkg, options) {
  const whitelist = (options.license && options.license.files) || pkg.files;
  const exclude = options.license && options.license.exclude;
  return addLicenseHeaders(cwd, whitelist, exclude);
}

function getPullRequestId() {
  const travisId = process.env.TRAVIS_PULL_REQUEST;

  if (travisId && travisId !== 'false') {
    return travisId;
  }

  const dotciId = process.env.DOTCI_PULL_REQUEST;

  if (dotciId && dotciId !== 'false') {
    return dotciId;
  }

  const circleCiPullUrl = process.env.CIRCLE_PULL_REQUEST;
  if (circleCiPullUrl && circleCiPullUrl !== 'false') {
    const circleCiId = circleCiPullUrl.split('/').pop();
    return circleCiId;
  }

  return '';
}

function verify(cwd, pkg, options) {
  try {
    fs.readdirSync(path.join(cwd, '.git'));
  } catch (err) {
    if (err.code === 'ENOENT') {
      return Promise.resolve();
    }

    throw err;
  }

  // Not making this configurable to prevent some possible abuse
  options.pr = getPullRequestId();

  function ensureLastVersionTag() {
    return ensureTag(cwd, `v${pkg.version}`);
  }

  function setReleaseType() {
    /* eslint no-console:0 */
    options.releaseType = determineReleaseInfo(
      options.commits,
      options.acceptInvalidCommits
    );
    const { releaseType } = options;
    const nextUpdate =
      releaseType !== 'none'
        ? `${pkg.version} -> ${semver.inc(pkg.version, releaseType)}`
        : '';
    console.log('[nlm] Changes are %j (%s)', releaseType, nextUpdate);
  }

  const verifyTasks = [
    ensureLastVersionTag,
    getPendingChanges,
    setReleaseType,
    verifyLicenseHeaders,
    verifyClean,
    detectBranch,
    tagPullRequest,
  ];

  function runTask(task) {
    return task(cwd, pkg, options);
  }

  async function runVerifyTasks() {
    for (const task of verifyTasks) await runTask(task);
  }

  return runVerifyTasks();
}

module.exports = verify;
<commit_msg>fix(verify): remove () from message<commit_after>/*
 * Copyright (c) 2015, Groupon, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 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.
 *
 * Neither the name of GROUPON nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * 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
 * HOLDER 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.
 */

'use strict';

const fs = require('fs');

const path = require('path');

const semver = require('semver');

const addLicenseHeaders = require('../license');

const verifyClean = require('../git/verify-clean');

const ensureTag = require('../git/ensure-tag');

const determineReleaseInfo = require('../steps/release-info');

const tagPullRequest = require('../steps/tag-pr');

const getPendingChanges = require('../steps/pending-changes');

const detectBranch = require('../steps/detect-branch');

function verifyLicenseHeaders(cwd, pkg, options) {
  const whitelist = (options.license && options.license.files) || pkg.files;
  const exclude = options.license && options.license.exclude;
  return addLicenseHeaders(cwd, whitelist, exclude);
}

function getPullRequestId() {
  const travisId = process.env.TRAVIS_PULL_REQUEST;

  if (travisId && travisId !== 'false') {
    return travisId;
  }

  const dotciId = process.env.DOTCI_PULL_REQUEST;

  if (dotciId && dotciId !== 'false') {
    return dotciId;
  }

  const circleCiPullUrl = process.env.CIRCLE_PULL_REQUEST;
  if (circleCiPullUrl && circleCiPullUrl !== 'false') {
    const circleCiId = circleCiPullUrl.split('/').pop();
    return circleCiId;
  }

  return '';
}

function verify(cwd, pkg, options) {
  try {
    fs.readdirSync(path.join(cwd, '.git'));
  } catch (err) {
    if (err.code === 'ENOENT') {
      return Promise.resolve();
    }

    throw err;
  }

  // Not making this configurable to prevent some possible abuse
  options.pr = getPullRequestId();

  function ensureLastVersionTag() {
    return ensureTag(cwd, `v${pkg.version}`);
  }

  function setReleaseType() {
    /* eslint no-console:0 */
    options.releaseType = determineReleaseInfo(
      options.commits,
      options.acceptInvalidCommits
    );
    const { releaseType } = options;
    const nextUpdate =
      releaseType !== 'none'
        ? `(${pkg.version} -> ${semver.inc(pkg.version, releaseType)})`
        : '';
    console.log('[nlm] Changes are %j %s', releaseType, nextUpdate);
  }

  const verifyTasks = [
    ensureLastVersionTag,
    getPendingChanges,
    setReleaseType,
    verifyLicenseHeaders,
    verifyClean,
    detectBranch,
    tagPullRequest,
  ];

  function runTask(task) {
    return task(cwd, pkg, options);
  }

  async function runVerifyTasks() {
    for (const task of verifyTasks) await runTask(task);
  }

  return runVerifyTasks();
}

module.exports = verify;
<|endoftext|>


<commit_before>$(function () {
    var socket = io.connect('http://' + location.host + '/monitor');

    var canvas = document.getElementById('Canvas');
    paper.setup(canvas);

    var fieldSize = 500;
    var viewPoint = new paper.Point(0,0);

    var canvasSize = paper.view.size;

    var beyCircles = new Array();

    var socketFPS = 0;
    var drawFPS = 0;

    var socketFPStext = new paper.PointText(new paper.Point(10, 20));
    var drawFPStext = new paper.PointText(new paper.Point(10, 40));
    socketFPStext.fillColor = 'black';
    drawFPStext.fillColor = 'black';

    var beys = [];

    var SVGURLs = ['/img/bey01.svg', '/img/img01.svg'];
    var SVGcache = {};

    var beyObjects = {};

    var emergeEffects = [];

    var project = new paper.Project(canvas);

    var setupTime = (new Date);

    nowLoadingText = new paper.PointText({
        point: paper.view.center,
        content: 'Now Loading...',
        fillColor: 'black',
        fontSize: 24,
        justification: 'center'
    });

    paper.view.draw();

    var getData = function (name) {
        return SVGcache[name] || $.ajax(
            name, {
                success: function (data) {
                    SVGcache[name] = data;
                }
            });
    };

    deferredObjects = [];
    for (var i = 0; i < SVGURLs.length; i++) {
        deferredObjects.push(getData(SVGURLs[i]));
    }

    var setup = function () {
        //tB[h~`
        var fieldShape = new paper.Path.Circle(viewPoint.add(paper.view.center), fieldSize);
        fieldShape.fillColor = '#ddd';

        paper.view.draw();

        //TCY
        paper.view.onResize = function (event) {
            canvasSize = paper.view.size;
            fieldShape.position = paper.view.center;
        }

        //XV
        socket.on('StageInfo', function (message) {
            beys = message;
            socketFPS++;
        });

        //`
        setInterval(function () {
            for (var session in beyObjects) {
                beyObjects[session].called = false; // custom property
            }

            beys.forEach(function (bey) {
                var beyLocate = new paper.Point(bey.point);

                if (beyObjects[bey.session]) {
                    var elapsedTime = ((new Date) - setupTime) / 1000;
                    var destAngle = Math.sin(elapsedTime / 2) * 500 - elapsedTime * 2000;

                    beyObjects[bey.session].position = beyLocate.add(paper.view.center);
                    beyObjects[bey.session].called = true;
                    beyObjects[bey.session].rotate(destAngle - beyObjects[bey.session].angle);
                    beyObjects[bey.session].angle = destAngle;
                    beyObjects[bey.session].speed = bey.speed;
                } else {
                    var beyObject = project.importSVG(SVGcache['/img/bey01.svg']);
                    var baseGroup = beyObject.children['base'];
                    var designGroup = beyObject.children['design'];

                    beyObject.position = beyLocate.add(paper.view.center);
                    beyObject.scale(bey.size / 150);
                    beyObject.angle = 0; // custom property
                    beyObject.dead = false; // custom property
                    beyObject.speed = bey.speed; //custom property

                    Math.seedrandom(bey.session);
                    var mainColor = new paper.Color({ 'hue': Math.random() * 360, 'saturation': 0.6 + Math.random() * 0.4, 'brightness': 0.6 + Math.random() * 0.4 });
                    if (Math.random() > 0.5) {
                        var accentColor = new paper.Color({ 'hue': mainColor.hue + Math.random() * 100 - 50, 'saturation': 0.6 + Math.random() * 0.4, 'brightness': mainColor.brightness - Math.random() * 0.4 - 0.2 })
                    } else {
                        var accentColor = new paper.Color({ 'hue': mainColor.hue + Math.random() * 30 + 20, 'saturation': 0.6 + Math.random() * 0.4, 'brightness': 0.6 + Math.random() * 0.4 })
                    }
                    if (Math.random() > 0.5) {
                        baseColor = mainColor;
                        designColor = accentColor;
                    } else {
                        baseColor = accentColor;
                        designColor = mainColor;
                    }

                    if (bey.isCPU == true) {
                        baseColor.saturation = 0;
                        designColor.saturation = 0;
                        baseColor.brightness = Math.max((baseColor.brightness - 0.6) * 2, 0);
                        designColor.brightness = Math.max(designColor.brightness - 0.6, 0);
                    }

                    baseGroup.fillColor = new paper.Color(baseColor);
                    designGroup.fillColor = new paper.Color(designColor);

                    beyObjects[bey.session] = beyObject;
                    beyObjects[bey.session].called = true;

                    var emergeEffect = new paper.Path.Circle(beyObject.position, 30);
                    emergeEffect.strokeColor = 'blue';
                    emergeEffect.strokeWidth = 5;

                    emergeEffects.push(emergeEffect);
                }
            })

            for (var session in beyObjects) {
                if (beyObjects[session].called == false && !beyObjects[session].dead) {
                    beyObjects[session].dead = true;
                    console.log('called');
                }
                if (beyObjects[session].dead) {
                    beyObjects[session].position = beyObjects[session].position.add([beyObjects[session].speed[0] / 180, beyObjects[session].speed[1] / 180]);
                    beyObjects[session].scale((beyObjects[session].bounds.width - 1) / beyObjects[session].bounds.width);
                    if (beyObjects[session].bounds.width < 1) {
                        beyObjects[session].remove();
                        delete beyObjects[session];
                        console.log('removed');
                    }
                }
            }

            emergeEffects.forEach( function (emergeEffect) {
                emergeEffect.strokeColor.alpha -= 0.03;
                emergeEffect.scale(1 + emergeEffect.strokeColor.alpha * 0.1);
                if (emergeEffect.strokeColor.alpha <= 0) {
                    emergeEffect.remove();
                    emergeEffects.splice(emergeEffects.indexOf(emergeEffect), 1);
                }
            });

            paper.view.draw();
            drawFPS++;
        }, 1000 / 60);

        setInterval(function () {
            socketFPStext.content = 'Socket FPS: ' + socketFPS;
            drawFPStext.content = 'Draw FPS: ' + drawFPS;
            socketFPS = 0;
            drawFPS = 0;
        }, 1000);
    }

    $.when.apply(null, deferredObjects).done(setup);
});<commit_msg>落下エフェクトの修正<commit_after>$(function () {
    var socket = io.connect('http://' + location.host + '/monitor');

    var canvas = document.getElementById('Canvas');
    paper.setup(canvas);

    var fieldSize = 500;
    var viewPoint = new paper.Point(0,0);

    var canvasSize = paper.view.size;

    var beyCircles = new Array();

    var socketFPS = 0;
    var drawFPS = 0;

    var socketFPStext = new paper.PointText(new paper.Point(10, 20));
    var drawFPStext = new paper.PointText(new paper.Point(10, 40));
    socketFPStext.fillColor = 'black';
    drawFPStext.fillColor = 'black';

    var beys = [];

    var SVGURLs = ['/img/bey01.svg', '/img/img01.svg'];
    var SVGcache = {};

    var beyObjects = {};

    var emergeEffects = [];

    var project = new paper.Project(canvas);

    var setupTime = (new Date);

    nowLoadingText = new paper.PointText({
        point: paper.view.center,
        content: 'Now Loading...',
        fillColor: 'black',
        fontSize: 24,
        justification: 'center'
    });

    paper.view.draw();

    var getData = function (name) {
        return SVGcache[name] || $.ajax(
            name, {
                success: function (data) {
                    SVGcache[name] = data;
                }
            });
    };

    deferredObjects = [];
    for (var i = 0; i < SVGURLs.length; i++) {
        deferredObjects.push(getData(SVGURLs[i]));
    }

    var setup = function () {
        //tB[h~`
        var fieldShape = new paper.Path.Circle(viewPoint.add(paper.view.center), fieldSize);
        fieldShape.fillColor = '#ddd';

        paper.view.draw();

        //TCY
        paper.view.onResize = function (event) {
            canvasSize = paper.view.size;
            fieldShape.position = paper.view.center;
        }

        //XV
        socket.on('StageInfo', function (message) {
            beys = message;
            socketFPS++;
        });

        //`
        setInterval(function () {
            for (var session in beyObjects) {
                beyObjects[session].called = false; // custom property
            }

            beys.forEach(function (bey) {
                var beyLocate = new paper.Point(bey.point);

                if (beyObjects[bey.session]) {
                    var elapsedTime = ((new Date) - setupTime) / 1000;
                    var destAngle = Math.sin(elapsedTime / 2) * 500 - elapsedTime * 2000;

                    beyObjects[bey.session].position = beyLocate.add(paper.view.center);
                    beyObjects[bey.session].called = true;
                    beyObjects[bey.session].rotate(destAngle - beyObjects[bey.session].angle);
                    beyObjects[bey.session].angle = destAngle;
                    beyObjects[bey.session].speed = bey.speed;
                } else {
                    var beyObject = project.importSVG(SVGcache['/img/bey01.svg']);
                    var baseGroup = beyObject.children['base'];
                    var designGroup = beyObject.children['design'];

                    beyObject.position = beyLocate.add(paper.view.center);
                    beyObject.scale(bey.size / 150);
                    beyObject.angle = 0; // custom property
                    beyObject.dead = false; // custom property
                    beyObject.speed = bey.speed; //custom property

                    Math.seedrandom(bey.session);
                    var mainColor = new paper.Color({ 'hue': Math.random() * 360, 'saturation': 0.6 + Math.random() * 0.4, 'brightness': 0.6 + Math.random() * 0.4 });
                    if (Math.random() > 0.5) {
                        var accentColor = new paper.Color({ 'hue': mainColor.hue + Math.random() * 100 - 50, 'saturation': 0.6 + Math.random() * 0.4, 'brightness': mainColor.brightness - Math.random() * 0.4 - 0.2 })
                    } else {
                        var accentColor = new paper.Color({ 'hue': mainColor.hue + Math.random() * 30 + 20, 'saturation': 0.6 + Math.random() * 0.4, 'brightness': 0.6 + Math.random() * 0.4 })
                    }
                    if (Math.random() > 0.5) {
                        baseColor = mainColor;
                        designColor = accentColor;
                    } else {
                        baseColor = accentColor;
                        designColor = mainColor;
                    }

                    if (bey.isCPU == true) {
                        baseColor.saturation = 0;
                        designColor.saturation = 0;
                        baseColor.brightness = Math.max((baseColor.brightness - 0.6) * 2, 0);
                        designColor.brightness = Math.max(designColor.brightness - 0.6, 0);
                    }

                    baseGroup.fillColor = new paper.Color(baseColor);
                    designGroup.fillColor = new paper.Color(designColor);

                    beyObjects[bey.session] = beyObject;
                    beyObjects[bey.session].called = true;

                    var emergeEffect = new paper.Path.Circle(beyObject.position, 30);
                    emergeEffect.strokeColor = 'blue';
                    emergeEffect.strokeWidth = 5;

                    emergeEffects.push(emergeEffect);
                }
            })

            for (var session in beyObjects) {
                if (beyObjects[session].called == false && !beyObjects[session].dead) {
                    beyObjects[session].dead = true;
                    console.log('called');
                }
                if (beyObjects[session].dead) {
                    var elapsedTime = ((new Date) - setupTime) / 1000;
                    var destAngle = Math.sin(elapsedTime / 2) * 500 - elapsedTime * 2000;

                    beyObjects[session].rotate(destAngle - beyObjects[session].angle);
                    beyObjects[session].angle = destAngle;
                    beyObjects[session].position = beyObjects[session].position.add([beyObjects[session].speed[0] / 180, beyObjects[session].speed[1] / 180]);
                    beyObjects[session].scale(0.95);
                    if (beyObjects[session].bounds.width < 1) {
                        beyObjects[session].remove();
                        delete beyObjects[session];
                        console.log('removed');
                    }
                }
            }

            emergeEffects.forEach( function (emergeEffect) {
                emergeEffect.strokeColor.alpha -= 0.03;
                emergeEffect.scale(1 + emergeEffect.strokeColor.alpha * 0.1);
                if (emergeEffect.strokeColor.alpha <= 0) {
                    emergeEffect.remove();
                    emergeEffects.splice(emergeEffects.indexOf(emergeEffect), 1);
                }
            });

            paper.view.draw();
            drawFPS++;
        }, 1000 / 60);

        setInterval(function () {
            socketFPStext.content = 'Socket FPS: ' + socketFPS;
            drawFPStext.content = 'Draw FPS: ' + drawFPS;
            socketFPS = 0;
            drawFPS = 0;
        }, 1000);
    }

    $.when.apply(null, deferredObjects).done(setup);
});<|endoftext|>


<commit_before>const q = require('q')
const EventEmitter = require('events').EventEmitter
const { MongoClient, ObjectId } = require('mongodb')
const Redis = require('redis')
const fs = require('fs')

module.exports = function (config) {
  Object.assign(exports, config.common.storage)
  return function storageConnect () {
    if (exports._connected) {
      return q.when()
    }

    let uri = `mongodb://${config.mongo.host}:${config.mongo.port}/${config.mongo.database}`
    delete config.mongo.host
    delete config.mongo.port
    delete config.mongo.database

    let redis = Redis.createClient(config.redis)
    let pub = Redis.createClient(config.redis)
    let sub = Redis.createClient(config.redis)

    let mongo = q.ninvoke(MongoClient, 'connect', uri, Object.assign({ promiseLibrary: Promise }, config.mongo))
      .then(db => {
        function wrapCollection (collection, cname) {
          let wrap = {}
          function keyToId (obj) {
            let idRegex = /^[a-f0-9]{24}$/
            if (obj instanceof Array) return obj.map(keyToId)
            if (obj._id && obj._id.$in) {
              return Object.assign({}, obj, {
                _id: {
                  $in: obj._id.$in.map(i => {
                    if (typeof i === 'string' && i.match(idRegex)) {
                      i = new ObjectId(i)
                    }
                    return i
                  })
                }
              })
            }
            if (typeof obj._id === 'string' && obj._id.match(idRegex)) {
              return Object.assign({}, obj, { _id: new ObjectId(obj._id) })
            }
            return obj
          }
          function idToKey (obj) {
            if (obj instanceof Array) return obj.map(idToKey)
            if (obj && obj._id) {
              obj._id = obj._id.toString()
            }
            return obj
          }
          ;['find', 'findOne', 'findEx', 'by', 'count', 'ensureIndex', 'remove', 'insert', 'update'].forEach(method => {
            wrap[method] = (...a) => {
              try {
                let orig = a[0]
                if (typeof a[0] === 'object') {
                  a[0] = keyToId(a[0])
                }
                if (method === 'update') {
                  a[2] = a[2] || {}
                  if (a[2].multi !== false) a[2].multi = true
                }
                let ex = method === 'findEx'
                if (ex) method = 'find'
                let chain = collection[method](...a)
                if (method === 'insert') {
                  chain = chain.then((n) => Object.assign(orig, n))
                }
                if (method === 'update') {
                  chain = chain.then((n) => Object.assign(n, { modified: n.result.nModified }))
                }
                if (ex) {
                  let opts = a[1]
                  if (opts.sort) {
                    chain = chain.sort(opts.sort)
                  }
                  if (opts.offset) {
                    chain = chain.offset(opts.offset)
                  }
                  if (opts.limit) {
                    chain = chain.limit(opts.limit)
                  }
                }
                if (method === 'find') {
                  chain = q.ninvoke(chain, 'toArray')
                }
                chain = chain.then(idToKey)
                  .catch(e => {
                    console.error('DBERR', e, ex)
                    console.log('DBERR', e.stack)
                  })
                return q(chain)
              } catch (e) {
                console.error('DBERR', e)
                console.log('DBERR', e.stack)
                return q(Promise.reject(e))
              }
            }
          })

          wrap.drop = (...a) => {
            return q.ninvoke(collection, 'drop', ...a).catch(e => q.resolve())
          }
          wrap.clear = wrap.drop
          wrap.removeWhere = wrap.remove
          wrap.by = (_id) => wrap.find({ _id })
          wrap.bulk = function (bulk, cb) {
            let batch = collection.initializeUnorderedBulkOp()
            try {
              bulk.forEach(i => {
                if (i.op === 'insert') {
                  return batch.insert(i.data)
                }
                let q = { _id: (i.id && i.id.length === 24) ? new ObjectId(i.id + '') : i.id }
                if (i.op === 'update') {
                  return batch.find(q).update({ $set: i.$set })
                }
                if (i.op === 'remove') {
                  return batch.find(q).remove()
                }
                if (i.op === 'inc') {
                  return batch.find(q).update({$inc: { [i.key]: i.amount }})
                }
                console.error('UNKNOWN BULK!', i)
              })
              return q.ninvoke(batch, 'execute')
            } catch (e) {
              if (cb) cb(e.message)
              console.error(e)
              return q.reject(e.message)
            }
          }
          return wrap
        }
        config.common.dbCollections.forEach(i => {
          let collection = db.collection(i)
          let indexes = config.common.dbIndexes[i]
          if (indexes) {
            for (let k in indexes) {
              collection.ensureIndex({ [k]: indexes[k] })
            }
          }
          exports.db[i] = wrapCollection(collection, i)
        })
      })

    Object.assign(exports.pubsub, {
      ee: new EventEmitter(),
      subscribed: {},
      publish (channel, data) {
        pub.publish(channel, data)
        return q.when()
      },
      subscribe (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.on(channel, cb)
        return q.when()
      },
      once (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.once(channel, cb)
        return q.when()
      }
    })
    sub.on('message', (channel, message) => {
      exports.pubsub.ee.emit(channel, message)
    })
    sub.on('pmessage', (pattern, channel, message) => {
      exports.pubsub.ee.emit(channel, message)
      exports.pubsub.ee.emit(pattern, channel, message)
    })

    Object.assign(exports.env, {
      get: q.nbind(redis.get, redis),
      mget: q.nbind(redis.mget, redis),
      set: q.nbind(redis.set, redis),
      setex: q.nbind(redis.setex, redis),
      expire: q.nbind(redis.expire, redis),
      ttl: q.nbind(redis.ttl, redis),
      del: q.nbind(redis.del, redis),
      hmget: q.nbind(redis.hmget, redis),
      hmset: q.nbind(redis.hmset, redis),
      hget: q.nbind(redis.hget, redis),
      hset: q.nbind(redis.hset, redis),
      hgetall: q.nbind(redis.hgetall, redis),
      incr: q.nbind(redis.incr, redis),
      flushall: q.nbind(redis.flushall, redis)
    })

    exports._connected = true
    exports.resetAllData = () => q.when() // Temp dummy

    Object.assign(exports.queue, require('./queue'))
    exports.queue.wrap(redis, exports.pubsub)

    let oget = exports.env.get
    exports.env.get = function (...a) {
      return oget(...a).catch(() => exports.env.hgetall(...a))
    }

    exports.resetAllData = () => {
      return exports.importDB(`${__dirname}/../../db.original.json`)
    }
    Object.assign(config.common.storage, exports)
    return mongo
  }
}

exports.importDB = function importDB (path = './db.json') {
  let { db, env } = exports
  console.log('Importing DB')
  try {
    let olddb = JSON.parse(fs.readFileSync(path).toString())
    let ps = olddb.collections.map(oldcol => {
      let name = oldcol.name
      console.log('Collection', name)
      if (name === 'env') {
        return env.flushall().then(() => {
          let p = oldcol.data.map(row => {
            let ps = []
            for (let k in row.data) {
              let v = row.data[k]
              ps.push(env.set(k, typeof v === 'object' ? JSON.stringify(v) : v))
            }
            return Promise.all(ps)
          })
          return Promise.all(p)
        })
      } else {
        return db[name].drop().then(() => Promise.all(oldcol.data.map(row => {
          delete row.meta
          delete row.$loki
          return db[name].insert(row)
        })))
      }
    })
    ps.push(db.users.update({ _id: '2' }, { $set: { _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ _id: '3' }, { $set: { _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    return Promise.all(ps)
      .then(() => console.log('Import complete. Restart the server for best results.'))
      .catch(e => importFail(e))
  } catch (e) {
    return importFail(e)
  }
}

function importFail (e) {
  let { db, env } = exports
  let ps = []
  ps.push(db.users.insert({ _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(env.set('gameTime', 1))
  return Promise.resolve()
    .then(() => console.log('An error occured importing existing db, initializing blank server'))
    .then(() => console.error(e))
    .then(() => Promise.all(ps))
    .then(() => console.log('Server initialzed. Remember to generate rooms.'))
    .catch(err => console.error(err))
}
<commit_msg>Fixed bug from recent bulk update<commit_after>const q = require('q')
const EventEmitter = require('events').EventEmitter
const { MongoClient, ObjectId } = require('mongodb')
const Redis = require('redis')
const fs = require('fs')

module.exports = function (config) {
  Object.assign(exports, config.common.storage)
  return function storageConnect () {
    if (exports._connected) {
      return q.when()
    }

    let uri = `mongodb://${config.mongo.host}:${config.mongo.port}/${config.mongo.database}`
    delete config.mongo.host
    delete config.mongo.port
    delete config.mongo.database

    let redis = Redis.createClient(config.redis)
    let pub = Redis.createClient(config.redis)
    let sub = Redis.createClient(config.redis)

    let mongo = q.ninvoke(MongoClient, 'connect', uri, Object.assign({ promiseLibrary: Promise }, config.mongo))
      .then(db => {
        function wrapCollection (collection, cname) {
          let wrap = {}
          function keyToId (obj) {
            let idRegex = /^[a-f0-9]{24}$/
            if (obj instanceof Array) return obj.map(keyToId)
            if (obj._id && obj._id.$in) {
              return Object.assign({}, obj, {
                _id: {
                  $in: obj._id.$in.map(i => {
                    if (typeof i === 'string' && i.match(idRegex)) {
                      i = new ObjectId(i)
                    }
                    return i
                  })
                }
              })
            }
            if (typeof obj._id === 'string' && obj._id.match(idRegex)) {
              return Object.assign({}, obj, { _id: new ObjectId(obj._id) })
            }
            return obj
          }
          function idToKey (obj) {
            if (obj instanceof Array) return obj.map(idToKey)
            if (obj && obj._id) {
              obj._id = obj._id.toString()
            }
            return obj
          }
          ;['find', 'findOne', 'findEx', 'by', 'count', 'ensureIndex', 'remove', 'insert', 'update'].forEach(method => {
            wrap[method] = (...a) => {
              try {
                let orig = a[0]
                if (typeof a[0] === 'object') {
                  a[0] = keyToId(a[0])
                }
                if (method === 'update') {
                  a[2] = a[2] || {}
                  if (a[2].multi !== false) a[2].multi = true
                }
                let ex = method === 'findEx'
                if (ex) method = 'find'
                let chain = collection[method](...a)
                if (method === 'insert') {
                  chain = chain.then((n) => Object.assign(orig, n))
                }
                if (method === 'update') {
                  chain = chain.then((n) => Object.assign(n, { modified: n.result.nModified }))
                }
                if (ex) {
                  let opts = a[1]
                  if (opts.sort) {
                    chain = chain.sort(opts.sort)
                  }
                  if (opts.offset) {
                    chain = chain.offset(opts.offset)
                  }
                  if (opts.limit) {
                    chain = chain.limit(opts.limit)
                  }
                }
                if (method === 'find') {
                  chain = q.ninvoke(chain, 'toArray')
                }
                chain = chain.then(idToKey)
                  .catch(e => {
                    console.error('DBERR', e, ex)
                    console.log('DBERR', e.stack)
                  })
                return q(chain)
              } catch (e) {
                console.error('DBERR', e)
                console.log('DBERR', e.stack)
                return q(Promise.reject(e))
              }
            }
          })

          wrap.drop = (...a) => {
            return q.ninvoke(collection, 'drop', ...a).catch(e => q.resolve())
          }
          wrap.clear = wrap.drop
          wrap.removeWhere = wrap.remove
          wrap.by = (_id) => wrap.find({ _id })
          wrap.bulk = function (bulk, cb) {
            let batch = collection.initializeUnorderedBulkOp()
            try {
              bulk.forEach(i => {
                if (i.op === 'insert') {
                  return batch.insert(i.data)
                }
                let q = { _id: (i.id && i.id.length === 24) ? new ObjectId(i.id + '') : i.id }
                if (i.op === 'update') {
                  return batch.find(q).update(i.update)
                }
                if (i.op === 'remove') {
                  return batch.find(q).remove()
                }
                console.error('UNKNOWN BULK!', i)
              })
              return q.ninvoke(batch, 'execute')
            } catch (e) {
              if (cb) cb(e.message)
              console.error(e)
              return q.reject(e.message)
            }
          }
          return wrap
        }
        config.common.dbCollections.forEach(i => {
          let collection = db.collection(i)
          let indexes = config.common.dbIndexes[i]
          if (indexes) {
            for (let k in indexes) {
              collection.ensureIndex({ [k]: indexes[k] })
            }
          }
          exports.db[i] = wrapCollection(collection, i)
        })
      })

    Object.assign(exports.pubsub, {
      ee: new EventEmitter(),
      subscribed: {},
      publish (channel, data) {
        pub.publish(channel, data)
        return q.when()
      },
      subscribe (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.on(channel, cb)
        return q.when()
      },
      once (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.once(channel, cb)
        return q.when()
      }
    })
    sub.on('message', (channel, message) => {
      exports.pubsub.ee.emit(channel, message)
    })
    sub.on('pmessage', (pattern, channel, message) => {
      exports.pubsub.ee.emit(channel, message)
      exports.pubsub.ee.emit(pattern, channel, message)
    })

    Object.assign(exports.env, {
      get: q.nbind(redis.get, redis),
      mget: q.nbind(redis.mget, redis),
      set: q.nbind(redis.set, redis),
      setex: q.nbind(redis.setex, redis),
      expire: q.nbind(redis.expire, redis),
      ttl: q.nbind(redis.ttl, redis),
      del: q.nbind(redis.del, redis),
      hmget: q.nbind(redis.hmget, redis),
      hmset: q.nbind(redis.hmset, redis),
      hget: q.nbind(redis.hget, redis),
      hset: q.nbind(redis.hset, redis),
      hgetall: q.nbind(redis.hgetall, redis),
      incr: q.nbind(redis.incr, redis),
      flushall: q.nbind(redis.flushall, redis)
    })

    exports._connected = true
    exports.resetAllData = () => q.when() // Temp dummy

    Object.assign(exports.queue, require('./queue'))
    exports.queue.wrap(redis, exports.pubsub)

    let oget = exports.env.get
    exports.env.get = function (...a) {
      return oget(...a).catch(() => exports.env.hgetall(...a))
    }

    exports.resetAllData = () => {
      return exports.importDB(`${__dirname}/../../db.original.json`)
    }
    Object.assign(config.common.storage, exports)
    return mongo
  }
}

exports.importDB = function importDB (path = './db.json') {
  let { db, env } = exports
  console.log('Importing DB')
  try {
    let olddb = JSON.parse(fs.readFileSync(path).toString())
    let ps = olddb.collections.map(oldcol => {
      let name = oldcol.name
      console.log('Collection', name)
      if (name === 'env') {
        return env.flushall().then(() => {
          let p = oldcol.data.map(row => {
            let ps = []
            for (let k in row.data) {
              let v = row.data[k]
              ps.push(env.set(k, typeof v === 'object' ? JSON.stringify(v) : v))
            }
            return Promise.all(ps)
          })
          return Promise.all(p)
        })
      } else {
        return db[name].drop().then(() => Promise.all(oldcol.data.map(row => {
          delete row.meta
          delete row.$loki
          return db[name].insert(row)
        })))
      }
    })
    ps.push(db.users.update({ _id: '2' }, { $set: { _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ _id: '3' }, { $set: { _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    return Promise.all(ps)
      .then(() => console.log('Import complete. Restart the server for best results.'))
      .catch(e => importFail(e))
  } catch (e) {
    return importFail(e)
  }
}

function importFail (e) {
  let { db, env } = exports
  let ps = []
  ps.push(db.users.insert({ _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(env.set('gameTime', 1))
  return Promise.resolve()
    .then(() => console.log('An error occured importing existing db, initializing blank server'))
    .then(() => console.error(e))
    .then(() => Promise.all(ps))
    .then(() => console.log('Server initialzed. Remember to generate rooms.'))
    .catch(err => console.error(err))
}
<|endoftext|>


<commit_before>/* In this app $rootScope is mostly used for
 * changing the route and managing visibly of navigation bar.
 */
Appbase.credentials("twitter", "2cac84749bc429ad7017bb1685eafaf4");
angular.module('twitter',['ngRoute','ngAppbase'])
  .run(function($rootScope,userSession,$location) {
    $rootScope.exit = function() {
      userSession.exit()
      $location.path('/global')
    }
    $rootScope.gotoProfile = function(userId){
      $location.path('/profile/'+userId)
    }
    $rootScope.search = function(text){
      $location.path('/search/'+text)
    }
    $rootScope.goHome = function(feed){
      $location.path('/home/'+feed)
    }
    $rootScope.hideNav = function (){
      $rootScope.$broadcast('hideNav',[1])
    }
    $rootScope.showNav = function (){
      $rootScope.$broadcast('showNav')
    }
    $rootScope.load = function() {
      $location.path('/loading')
    }
  })
  // Route management
  .config(function($routeProvider){
    $routeProvider
      .when('/',
      {
        controller:'global',
        templateUrl:'views/global.html'
      }
    ).when('/loading',
      {
        controller:'loading',
        templateUrl:'views/loading.html'
      }
    ).when('/search/:text',
      {
        controller:'search',
        templateUrl:'views/search.html'
      }
    ).when('/profile/:userId',
      {
        controller:'profile',
        templateUrl:'views/profile.html'
      }
    ).when('/home/:feed',
      {
        controller:'home',
        templateUrl:'views/home.html'
      }
    ).otherwise({redirectTo:'/'})
  })
  /* Controller: global
   * Shows all tweets when no one is logged in
   */
  .controller('global', function ($scope, userSession, $location,$rootScope,$appbaseRef) {
    // Navigation bar shouldn't be visible if no one is logged in
    $rootScope.hideNav()

    // Called when the user enter a name, or the user is already logged in
    $scope.login = function() {
      userSession.setUser($scope.userId.replace(/ /g, "_"))
      $location.path('/loading')
    }
    // Check if a user is already logged in the session
    if( $scope.userId = userSession.getUser()){
      $scope.login()
    }
    //Show all tweets
    $appbaseRef('global/tweets').$bindEdges($scope,'tweets')
  })
  /* Controller: search
   * Search's for tweets in Appbase and shows results
   */
  .controller('search', function ($scope, $rootScope, $routeParams) {
    // Getting the 'query text' from route parameters
    $scope.currentQuery = $routeParams.text
    // Searching in the namespace: __tweet__ for vertices, which contain 'query text' in the property: __msg__
    Appbase.search('tweet',{text: $routeParams.text, properties:['msg']},function(error, array) {
      $scope.tweets = array
      $scope.$apply()
    })
  })
  /* Controller: Loading
   * It inits the __data__ factory, which is used everywhere in the app to fetch and set data from/to Appbase.
   * After the _init_ completes, it takes the user to _home_ screen, showing personal tweets of the user.
   */
  .controller('loading', function ($rootScope,$scope, userSession, data) {
    if(!userSession.getUser()){
      $rootScope.exit()
      return
    }
    data.init(function() {
      $scope.$apply(function() {
        $rootScope.goHome('personal')
      })
    })
  })
  /* Controller: navbar
   * Handles button clicks and visibility of buttons
   */
  .controller('navbar',function($scope,userSession,$location,$rootScope,$routeParams){
    $scope.bahar = true
    // Called when user enters a text in the search box and presses Enter key
    $scope.search = function() {
      $rootScope.search($scope.searchText)
      $scope.searchText = ''
    }
    $scope.$on('showNav',function() {
      $scope.bahar = false
    })
    $scope.$on('hideNav',function() {
      $scope.bahar = true
    })
    $scope.exit= function() {
      $rootScope.exit()
    }
    $scope.gotoProfile= function(userId){
      if(userId === undefined)
        var userId = userSession.getUser()
      $rootScope.gotoProfile(userId)
    }
    $scope.goHome = function(feed){
      $rootScope.goHome(feed)
    }
  })
  /* Controller: home
   * This is what the user sees first when logged in. It shows the personal and global tweet feeds
   * The personal tweet feed: shows tweets from people he follows
   * The global feed: tweets by everyone
   */
  .controller('home',function($scope,userSession,$location,$rootScope,$appbaseRef,$routeParams,data){
    // Check if the session is properly initiated,
    // i.e. the 'data' factory set the flag 'initComplete' in userSession
    if(!userSession.initComplete) {
      if(!userSession.getUser())
        $rootScope.exit()
      else
        $rootScope.load()
      return
    }
    $rootScope.showNav()
    //Get __feed__ from route parameters
    var feed = $routeParams.feed === undefined? 'global': $routeParams.feed
    $scope.tweets = []
    $scope.people = []
    $scope.userName = userSession.getUser()
    $scope.gotoProfile = $rootScope.gotoProfile
    //Show _People on Twitter_, user's _Followers_ and _Followings_
    $appbaseRef(data.refs.allUsers).$bindEdges($scope,'people')
    $appbaseRef(data.refs.usersFollowers).$bindEdges($scope,'followers')
    $appbaseRef(data.refs.usersFollowing).$bindEdges($scope,'following')

    //Called when user posts a new tweet
    $scope.addTweet = function() {
      data.addTweet($scope.msg)
      $scope.msg = ''
    }
    if(feed === 'global') {
      // Show all tweets
      $appbaseRef(data.refs.globalTweets).$bindEdges($scope,'tweets')
    } else {
      /* Fetch tweets of the people followed by the user. Every following's tweets are pushed into `arraysOfTweets` as an array,
       * and in the end, these arrays are merged into personalTweets by calling `personalTweets.concat.apply(personalTweets, arraysOfTweets)`
       * in _home.html_
       */
      $scope.personalTweets = []
      $scope.arraysOfTweets = []
      $scope.arraysOfTweets.push($appbaseRef('user/'+userSession.getUser()+'/tweets').$bindEdges($scope))
      var usrRef = Appbase.ref('user/'+userSession.getUser()+'/following')
      usrRef.on('edge_added',function(error, followUserRef) {
        if(error) throw error
        $scope.arraysOfTweets.push($appbaseRef(followUserRef).$outVertex('tweets').$bindEdges($scope))
      })
      $scope.$on('$destroy',function() {
        //Stop listening to user's followings when the view is destroyed.
        usrRef.off()
      })
    }
  })
  /* Controller: profile
   * Where a user's followings, followers and tweets are shown.
   * A user can also see other's profiles and choose to follow/unfollow the person from his/her profile.
   */
  .controller('profile',function($scope,userSession,$location,$rootScope,$routeParams,$appbaseRef,data){
    if(!userSession.initComplete) {
      if(!userSession.getUser())
        $rootScope.exit()
      else
        $rootScope.load()
      return
    }
    $rootScope.showNav()

    //Get the userId from route params
    var userId = $routeParams.userId
    $scope.userId = $routeParams.userId
    //Check whether this profile is of the logged in user
    $scope.isMe = userSession.getUser() === userId
    $scope.userName = $routeParams.userId
    $scope.isReady = false

    //Check whether this user is being followed by the logged in user
    // This has to be an async function, as it interacts with the Appbase server
    !$scope.isMe && data.isUserBeingFollowed(userId,function(boolean){
      //If true, _unfollow_ button will appear, otherwise _follow_ one
      $scope.isBeingFollowed = boolean
      //Show _follow_ or _unfollow_ buttons only when the data is arrived
      $scope.isReady = true
    })
    $scope.gotoProfile = $rootScope.gotoProfile
    $scope.follow = function(userId){
      $scope.isBeingFollowed = true
      data.follow(userId)
    }
    $scope.unFollow = function(userId){
      $scope.isBeingFollowed = false
      data.unFollow(userId)
    }
    $scope.addTweet = function() {
      data.addTweet($scope.msg)
      $scope.msg = ''
    }
    //Fetch user's followers, followings and tweets
    $appbaseRef('user/'+userId+'/followers').$bindEdges($scope,'followers')
    $appbaseRef('user/'+userId+'/following').$bindEdges($scope,'following')
    $appbaseRef('user/'+userId+'/tweets').$bindEdges($scope,'tweets')
  })
  /*
   * Factory: data
   * Stores frequently useful Appbase references and interacts with Appbase for data needs
   */
  .factory('data',function(userSession) {
    // Appbase references
    var refs = {
      globalTweets: Appbase.ref('global/tweets'),
      allUsers: Appbase.ref('global/users')
    }
    // Factory to be exported
    var data = {
      refs:refs
    }
    // Called when the user just logs in.
    // It sets required references and creates basic data for a new user
    data.init = function(ready) {
      var userId = userSession.getUser()
      refs.user = Appbase.create('user',userSession.getUser())
      refs.usersTweets = refs.user.outVertex('tweets')
      refs.usersFollowers = refs.user.outVertex('followers')
      refs.usersFollowing = refs.user.outVertex('following')
      refs.user.on('properties',function(error, ref, snap) {
        refs.user.off()
        if(error) throw error
        if (snap.properties().name === undefined) {
          // The user logged in for the first time
          Appbase.ref('global/users').setEdge(refs.user,userId)
          // Set user's name
          refs.user.setData({
            name: userId
          })
          // Create vertices which will store user's followers, followings and tweets
          refs.user.setEdge(Appbase.create('misc',Appbase.uuid()),'tweets',function(error){
            if(error) throw error
            refs.user.setEdge(Appbase.create('misc',Appbase.uuid()),'followers', function(error){
              if(error) throw error
              refs.user.setEdge(Appbase.create('misc',Appbase.uuid()),'following', function(error){
                if(error) throw error
                //Set the flag true in userSession
                userSession.initComplete = true
                ready()
              })
            })
          })
        } else {
          //The user exists in Appbase
          userSession.initComplete = true
          ready()
        }
      })
    }
    data.addTweet = function(msg) {
      //Create a new 'tweet' vertex and store the tweet message
      var tweetRef = Appbase.create('tweet',Appbase.uuid())
      tweetRef.setData({ 'msg': msg, 'by': userSession.getUser() },function(error, tweetRef) {
        if(error) throw error
        //Add this tweet as an edge, in user's own tweets and global tweets.
        //We really don't care about the edge's name here
        var randomEdgeName = Appbase.uuid()
        refs.usersTweets.setEdge(tweetRef,randomEdgeName)
        refs.globalTweets.setEdge(tweetRef,randomEdgeName)
      })
    }
    // Checks whether provided userId is being followed by the logged in user
    data.isUserBeingFollowed = function(userId,callback){
      refs.usersFollowing.outVertex(userId).isValid(function(error, bool){
        if(error) throw error
        callback(bool)
      })
    }
    data.follow = function(userId) {
      refs.usersFollowing.setEdge(Appbase.ref('user/'+userId),userId)
      Appbase.ref('user/'+userId+'/followers').setEdge(refs.user,userSession.getUser())
    }
    data.unFollow = function(userId) {
      refs.usersFollowing.removeEdge(userId)
      Appbase.ref('user/'+userId+'/followers').removeEdge(userSession.getUser())
    }
    return data
  })
  // Stores logged in user's id.
  .factory('userSession',function() {
    var userSession = {}
    userSession.initComplete = false
    userSession.setUser = function(userId){
      localStorage.setItem("currentLoggedInUser", userId)
    }
    userSession.exit = function(){
      localStorage.removeItem("currentLoggedInUser")
    }
    userSession.getUser = function(){
      return localStorage.getItem("currentLoggedInUser")
    }
    return userSession
  })<commit_msg>Change app name to aphrodite<commit_after>/* In this app $rootScope is mostly used for
 * changing the route and managing visibly of navigation bar.
 */
Appbase.credentials("aphrodite", "4d8d0072580912343cd74a09015cd217");
angular.module('twitter',['ngRoute','ngAppbase'])
  .run(function($rootScope,userSession,$location) {
    $rootScope.exit = function() {
      userSession.exit()
      $location.path('/global')
    }
    $rootScope.gotoProfile = function(userId){
      $location.path('/profile/'+userId)
    }
    $rootScope.search = function(text){
      $location.path('/search/'+text)
    }
    $rootScope.goHome = function(feed){
      $location.path('/home/'+feed)
    }
    $rootScope.hideNav = function (){
      $rootScope.$broadcast('hideNav',[1])
    }
    $rootScope.showNav = function (){
      $rootScope.$broadcast('showNav')
    }
    $rootScope.load = function() {
      $location.path('/loading')
    }
  })
  // Route management
  .config(function($routeProvider){
    $routeProvider
      .when('/',
      {
        controller:'global',
        templateUrl:'views/global.html'
      }
    ).when('/loading',
      {
        controller:'loading',
        templateUrl:'views/loading.html'
      }
    ).when('/search/:text',
      {
        controller:'search',
        templateUrl:'views/search.html'
      }
    ).when('/profile/:userId',
      {
        controller:'profile',
        templateUrl:'views/profile.html'
      }
    ).when('/home/:feed',
      {
        controller:'home',
        templateUrl:'views/home.html'
      }
    ).otherwise({redirectTo:'/'})
  })
  /* Controller: global
   * Shows all tweets when no one is logged in
   */
  .controller('global', function ($scope, userSession, $location,$rootScope,$appbaseRef) {
    // Navigation bar shouldn't be visible if no one is logged in
    $rootScope.hideNav()

    // Called when the user enter a name, or the user is already logged in
    $scope.login = function() {
      userSession.setUser($scope.userId.replace(/ /g, "_"))
      $location.path('/loading')
    }
    // Check if a user is already logged in the session
    if( $scope.userId = userSession.getUser()){
      $scope.login()
    }
    //Show all tweets
    $appbaseRef('global/tweets').$bindEdges($scope,'tweets')
  })
  /* Controller: search
   * Search's for tweets in Appbase and shows results
   */
  .controller('search', function ($scope, $rootScope, $routeParams) {
    // Getting the 'query text' from route parameters
    $scope.currentQuery = $routeParams.text
    // Searching in the namespace: __tweet__ for vertices, which contain 'query text' in the property: __msg__
    Appbase.search('tweet',{text: $routeParams.text, properties:['msg']},function(error, array) {
      $scope.tweets = array
      $scope.$apply()
    })
  })
  /* Controller: Loading
   * It inits the __data__ factory, which is used everywhere in the app to fetch and set data from/to Appbase.
   * After the _init_ completes, it takes the user to _home_ screen, showing personal tweets of the user.
   */
  .controller('loading', function ($rootScope,$scope, userSession, data) {
    if(!userSession.getUser()){
      $rootScope.exit()
      return
    }
    data.init(function() {
      $scope.$apply(function() {
        $rootScope.goHome('personal')
      })
    })
  })
  /* Controller: navbar
   * Handles button clicks and visibility of buttons
   */
  .controller('navbar',function($scope,userSession,$location,$rootScope,$routeParams){
    $scope.bahar = true
    // Called when user enters a text in the search box and presses Enter key
    $scope.search = function() {
      $rootScope.search($scope.searchText)
      $scope.searchText = ''
    }
    $scope.$on('showNav',function() {
      $scope.bahar = false
    })
    $scope.$on('hideNav',function() {
      $scope.bahar = true
    })
    $scope.exit= function() {
      $rootScope.exit()
    }
    $scope.gotoProfile= function(userId){
      if(userId === undefined)
        var userId = userSession.getUser()
      $rootScope.gotoProfile(userId)
    }
    $scope.goHome = function(feed){
      $rootScope.goHome(feed)
    }
  })
  /* Controller: home
   * This is what the user sees first when logged in. It shows the personal and global tweet feeds
   * The personal tweet feed: shows tweets from people he follows
   * The global feed: tweets by everyone
   */
  .controller('home',function($scope,userSession,$location,$rootScope,$appbaseRef,$routeParams,data){
    // Check if the session is properly initiated,
    // i.e. the 'data' factory set the flag 'initComplete' in userSession
    if(!userSession.initComplete) {
      if(!userSession.getUser())
        $rootScope.exit()
      else
        $rootScope.load()
      return
    }
    $rootScope.showNav()
    //Get __feed__ from route parameters
    var feed = $routeParams.feed === undefined? 'global': $routeParams.feed
    $scope.tweets = []
    $scope.people = []
    $scope.userName = userSession.getUser()
    $scope.gotoProfile = $rootScope.gotoProfile
    //Show _People on Twitter_, user's _Followers_ and _Followings_
    $appbaseRef(data.refs.allUsers).$bindEdges($scope,'people')
    $appbaseRef(data.refs.usersFollowers).$bindEdges($scope,'followers')
    $appbaseRef(data.refs.usersFollowing).$bindEdges($scope,'following')

    //Called when user posts a new tweet
    $scope.addTweet = function() {
      data.addTweet($scope.msg)
      $scope.msg = ''
    }
    if(feed === 'global') {
      // Show all tweets
      $appbaseRef(data.refs.globalTweets).$bindEdges($scope,'tweets')
    } else {
      /* Fetch tweets of the people followed by the user. Every following's tweets are pushed into `arraysOfTweets` as an array,
       * and in the end, these arrays are merged into personalTweets by calling `personalTweets.concat.apply(personalTweets, arraysOfTweets)`
       * in _home.html_
       */
      $scope.personalTweets = []
      $scope.arraysOfTweets = []
      $scope.arraysOfTweets.push($appbaseRef('user/'+userSession.getUser()+'/tweets').$bindEdges($scope))
      var usrRef = Appbase.ref('user/'+userSession.getUser()+'/following')
      usrRef.on('edge_added',function(error, followUserRef) {
        if(error) throw error
        $scope.arraysOfTweets.push($appbaseRef(followUserRef).$outVertex('tweets').$bindEdges($scope))
      })
      $scope.$on('$destroy',function() {
        //Stop listening to user's followings when the view is destroyed.
        usrRef.off()
      })
    }
  })
  /* Controller: profile
   * Where a user's followings, followers and tweets are shown.
   * A user can also see other's profiles and choose to follow/unfollow the person from his/her profile.
   */
  .controller('profile',function($scope,userSession,$location,$rootScope,$routeParams,$appbaseRef,data){
    if(!userSession.initComplete) {
      if(!userSession.getUser())
        $rootScope.exit()
      else
        $rootScope.load()
      return
    }
    $rootScope.showNav()

    //Get the userId from route params
    var userId = $routeParams.userId
    $scope.userId = $routeParams.userId
    //Check whether this profile is of the logged in user
    $scope.isMe = userSession.getUser() === userId
    $scope.userName = $routeParams.userId
    $scope.isReady = false

    //Check whether this user is being followed by the logged in user
    // This has to be an async function, as it interacts with the Appbase server
    !$scope.isMe && data.isUserBeingFollowed(userId,function(boolean){
      //If true, _unfollow_ button will appear, otherwise _follow_ one
      $scope.isBeingFollowed = boolean
      //Show _follow_ or _unfollow_ buttons only when the data is arrived
      $scope.isReady = true
    })
    $scope.gotoProfile = $rootScope.gotoProfile
    $scope.follow = function(userId){
      $scope.isBeingFollowed = true
      data.follow(userId)
    }
    $scope.unFollow = function(userId){
      $scope.isBeingFollowed = false
      data.unFollow(userId)
    }
    $scope.addTweet = function() {
      data.addTweet($scope.msg)
      $scope.msg = ''
    }
    //Fetch user's followers, followings and tweets
    $appbaseRef('user/'+userId+'/followers').$bindEdges($scope,'followers')
    $appbaseRef('user/'+userId+'/following').$bindEdges($scope,'following')
    $appbaseRef('user/'+userId+'/tweets').$bindEdges($scope,'tweets')
  })
  /*
   * Factory: data
   * Stores frequently useful Appbase references and interacts with Appbase for data needs
   */
  .factory('data',function(userSession) {
    // Appbase references
    var refs = {
      globalTweets: Appbase.ref('global/tweets'),
      allUsers: Appbase.ref('global/users')
    }
    // Factory to be exported
    var data = {
      refs:refs
    }
    // Called when the user just logs in.
    // It sets required references and creates basic data for a new user
    data.init = function(ready) {
      var userId = userSession.getUser()
      refs.user = Appbase.create('user',userSession.getUser())
      refs.usersTweets = refs.user.outVertex('tweets')
      refs.usersFollowers = refs.user.outVertex('followers')
      refs.usersFollowing = refs.user.outVertex('following')
      refs.user.on('properties',function(error, ref, snap) {
        refs.user.off()
        if(error) throw error
        if (snap.properties().name === undefined) {
          // The user logged in for the first time
          Appbase.ref('global/users').setEdge(refs.user,userId)
          // Set user's name
          refs.user.setData({
            name: userId
          })
          // Create vertices which will store user's followers, followings and tweets
          refs.user.setEdge(Appbase.create('misc',Appbase.uuid()),'tweets',function(error){
            if(error) throw error
            refs.user.setEdge(Appbase.create('misc',Appbase.uuid()),'followers', function(error){
              if(error) throw error
              refs.user.setEdge(Appbase.create('misc',Appbase.uuid()),'following', function(error){
                if(error) throw error
                //Set the flag true in userSession
                userSession.initComplete = true
                ready()
              })
            })
          })
        } else {
          //The user exists in Appbase
          userSession.initComplete = true
          ready()
        }
      })
    }
    data.addTweet = function(msg) {
      //Create a new 'tweet' vertex and store the tweet message
      var tweetRef = Appbase.create('tweet',Appbase.uuid())
      tweetRef.setData({ 'msg': msg, 'by': userSession.getUser() },function(error, tweetRef) {
        if(error) throw error
        //Add this tweet as an edge, in user's own tweets and global tweets.
        //We really don't care about the edge's name here
        var randomEdgeName = Appbase.uuid()
        refs.usersTweets.setEdge(tweetRef,randomEdgeName)
        refs.globalTweets.setEdge(tweetRef,randomEdgeName)
      })
    }
    // Checks whether provided userId is being followed by the logged in user
    data.isUserBeingFollowed = function(userId,callback){
      refs.usersFollowing.outVertex(userId).isValid(function(error, bool){
        if(error) throw error
        callback(bool)
      })
    }
    data.follow = function(userId) {
      refs.usersFollowing.setEdge(Appbase.ref('user/'+userId),userId)
      Appbase.ref('user/'+userId+'/followers').setEdge(refs.user,userSession.getUser())
    }
    data.unFollow = function(userId) {
      refs.usersFollowing.removeEdge(userId)
      Appbase.ref('user/'+userId+'/followers').removeEdge(userSession.getUser())
    }
    return data
  })
  // Stores logged in user's id.
  .factory('userSession',function() {
    var userSession = {}
    userSession.initComplete = false
    userSession.setUser = function(userId){
      localStorage.setItem("currentLoggedInUser", userId)
    }
    userSession.exit = function(){
      localStorage.removeItem("currentLoggedInUser")
    }
    userSession.getUser = function(){
      return localStorage.getItem("currentLoggedInUser")
    }
    return userSession
  })<|endoftext|>