<commit_before>// ==UserScript==
// @name        Smart QR
// @namespace   http://tampermonkey.net/
// @description Detect links to phone numbers and locations and displays their value as a QR code on mouseover.
// @include     http://*
// @include     https://*
// @version     0.1
// ==/UserScript==

(function () {

  function addQR(value) {
    //console.log(value);
    if (value == '') {
      return;
    }
    i.src = 'https://chart.apis.google.com/chart?cht=qr&chs=100x100&chld=L|0&chl=' + encodeURIComponent(value);
    i.style.visibility = "visible";
  };

  function removeQR() {
    i.style.visibility = "hidden";
  };

  function addListeners(element, value) {
    element.addEventListener('mouseover', function() { addQR(value); } );
    element.addEventListener('mouseout', function() { removeQR(); });
    element.smartQRvalue = value;
  }

  function handleTextSelect(event) {
    var selection = document.getSelection();
    var text = selection.toString();
    if (text == '') {
      removeQR();
    }
    // Geo coordinates.
    // Match selections like "12.34 , 56.789".
    var re = new RegExp('^\\s*([0-9]\+\.[0-9]\+)\\s*(,\|;)\\s*([0-9]\+\.[0-9]\+)\\s*$');
    var matches = text.match(re);
    if (matches) {
			var value = 'geo:' + matches[1] + ',' + matches[3];
      addQR(value);
      return;
    }
    // Phone number.
    var re = new RegExp('^[^a-zA-Z]*$');
    var matches = text.match(re);
    if (matches) {
      var number = matches[0].replace(/[^0-9\+]/g, '');
      if (number == '') {
        return;
      }
      number = 'tel:' + number;
      addQR(number);
      return;
    }
  }

  function parseAndAddListeners() {
    var elements = document.getElementsByTagName('a');
    for(var i=0, len=elements.length; i < len; i++){
      var element = elements[i];
      if (element.href) {
        // elements with href="tel:..."
        var re = new RegExp('^tel:(.*)$');
        var matches = element.href.match(re);
        if (matches) {
          addListeners(element, element.href);
        }
        // elements with href="maps.google.com/?.*q=12,34"
        var re = new RegExp('maps.google.com.*q=([0-9\.]*),([0-9\.]*)');
        var matches = element.href.match(re);
        if (matches) {
          var value = 'geo:' + matches[1] + ',' + matches[2];
          addListeners(element, value);
        }
        // elements with href="@12.34,56.78"
        var re = new RegExp('google.*@([0-9]\+\.[0-9]\+),([0-9]\+\.[0-9]\+)');
        var matches = element.href.match(re);
        if (matches) {
          var value = 'geo:' + matches[1] + ',' + matches[2];
          addListeners(element, value);
        }
        // Wikipedia location elements.
        if (currentURL.hostname.match(/wikipedia\.org/)) {
          var re = new RegExp('tools.wmflabs.org/geohack/geohack\.php.*params=([0-9\.]*)_._([0-9\.]*)');
          var matches = element.href.match(re);
          if (matches) {
            var value = 'geo:' + matches[1] + ',' + matches[2];
            addListeners(element, value);
          }
        }
        // Openstreetmap coordinate link.
        if (currentURL.hostname.match(/openstreetmap\.org/)) {
          var re = new RegExp('/#map=[0-9]+/([0-9\.]+)/([0-9\.]+)');
          var matches = element.href.match(re);
          if (matches) {
            var value = 'geo:' + matches[1] + ',' + matches[2];
            addListeners(element, value);
          }
        }
        // Any "geo:" link.
        var re = new RegExp('geo:([0-9\.]+),([0-9\.]+)');
        var matches = element.href.match(re);
        if (matches) {
          var value = 'geo:' + matches[1] + ',' + matches[2];
          addListeners(element, value);
        }
      }
      // elements with data-number.
      if (element.dataset) {
        if (element.dataset.number) {
          addListeners(element, element.dataset.number);
        }
      }
    }
    // Facebook events, location.
    if (currentURL.hostname.match(/facebook\.com/)) {
      var elements = document.getElementsByTagName('img');
      for(var i=0, len=elements.length; i < len; i++){
        var element = elements[i];
        if (element.src) {
          var re = new RegExp('markers=([0-9\.]+)%2C([0-9\.]+)');
          var matches = element.src.match(re);
          if (matches) {
            var value = 'geo:' + matches[1] + ',' + matches[2];
            addListeners(element, value);
          }
        }
      }
    }
    // Google maps, info sidebar, phone numbers
    if (currentURL.hostname.match(/google/)) {
      var elements = document.getElementsByTagName('button');
      for(var i=0, len=elements.length; i < len; i++){
        var element = elements[i];
        if (element.dataset) {
          if (element.dataset.href) {
            addListeners(element, element.dataset.href);
          }
        }
      }
    }
    // Text selections.
    document.addEventListener('mouseup', handleTextSelect);
  }

  function manualTriggerWithDblClick() {
    window.addEventListener('dblclick', parseAndAddListeners, true);
  }

  function parseURL(url) {
    var parser = document.createElement('a');
    parser.href = url;
    return parser;
  }

  "use strict";

  var currentURL = parseURL(window.location.href);

  // Create code and add to body.
  var i = document.createElement("img");
  i.style.width = "100px";
  i.style.height = "100px";
  i.style.position = "fixed";
  i.style.left = "10px";
  i.style.bottom = "30px";
  i.style.zIndex = "999";
  i.style.visibility = "hidden";
  i.alt = "QR Code";

  document.body.appendChild(i);

  parseAndAddListeners();
  manualTriggerWithDblClick();

}());

<commit_msg>Metadata.<commit_after>// ==UserScript==
// @name        Smart QR
// @namespace   http://tampermonkey.net/
// @description Detect links to phone numbers and locations and displays their value as a QR code on mouseover.
// @copyright   2017, Georg Jähnig
// @include     http://*
// @include     https://*
// @version     0.1
// ==/UserScript==
//
// ==OpenUserJS==
// @author jorges
// ==/OpenUserJS==

(function () {

  function addQR(value) {
    //console.log(value);
    if (value == '') {
      return;
    }
    i.src = 'https://chart.apis.google.com/chart?cht=qr&chs=100x100&chld=L|0&chl=' + encodeURIComponent(value);
    i.style.visibility = "visible";
  };

  function removeQR() {
    i.style.visibility = "hidden";
  };

  function addListeners(element, value) {
    element.addEventListener('mouseover', function() { addQR(value); } );
    element.addEventListener('mouseout', function() { removeQR(); });
    element.smartQRvalue = value;
  }

  function handleTextSelect(event) {
    var selection = document.getSelection();
    var text = selection.toString();
    if (text == '') {
      removeQR();
    }
    // Geo coordinates.
    // Match selections like "12.34 , 56.789".
    var re = new RegExp('^\\s*([0-9]\+\.[0-9]\+)\\s*(,\|;)\\s*([0-9]\+\.[0-9]\+)\\s*$');
    var matches = text.match(re);
    if (matches) {
			var value = 'geo:' + matches[1] + ',' + matches[3];
      addQR(value);
      return;
    }
    // Phone number.
    var re = new RegExp('^[^a-zA-Z]*$');
    var matches = text.match(re);
    if (matches) {
      var number = matches[0].replace(/[^0-9\+]/g, '');
      if (number == '') {
        return;
      }
      number = 'tel:' + number;
      addQR(number);
      return;
    }
  }

  function parseAndAddListeners() {
    var elements = document.getElementsByTagName('a');
    for(var i=0, len=elements.length; i < len; i++){
      var element = elements[i];
      if (element.href) {
        // elements with href="tel:..."
        var re = new RegExp('^tel:(.*)$');
        var matches = element.href.match(re);
        if (matches) {
          addListeners(element, element.href);
        }
        // elements with href="maps.google.com/?.*q=12,34"
        var re = new RegExp('maps.google.com.*q=([0-9\.]*),([0-9\.]*)');
        var matches = element.href.match(re);
        if (matches) {
          var value = 'geo:' + matches[1] + ',' + matches[2];
          addListeners(element, value);
        }
        // elements with href="@12.34,56.78"
        var re = new RegExp('google.*@([0-9]\+\.[0-9]\+),([0-9]\+\.[0-9]\+)');
        var matches = element.href.match(re);
        if (matches) {
          var value = 'geo:' + matches[1] + ',' + matches[2];
          addListeners(element, value);
        }
        // Wikipedia location elements.
        if (currentURL.hostname.match(/wikipedia\.org/)) {
          var re = new RegExp('tools.wmflabs.org/geohack/geohack\.php.*params=([0-9\.]*)_._([0-9\.]*)');
          var matches = element.href.match(re);
          if (matches) {
            var value = 'geo:' + matches[1] + ',' + matches[2];
            addListeners(element, value);
          }
        }
        // Openstreetmap coordinate link.
        if (currentURL.hostname.match(/openstreetmap\.org/)) {
          var re = new RegExp('/#map=[0-9]+/([0-9\.]+)/([0-9\.]+)');
          var matches = element.href.match(re);
          if (matches) {
            var value = 'geo:' + matches[1] + ',' + matches[2];
            addListeners(element, value);
          }
        }
        // Any "geo:" link.
        var re = new RegExp('geo:([0-9\.]+),([0-9\.]+)');
        var matches = element.href.match(re);
        if (matches) {
          var value = 'geo:' + matches[1] + ',' + matches[2];
          addListeners(element, value);
        }
      }
      // elements with data-number.
      if (element.dataset) {
        if (element.dataset.number) {
          addListeners(element, element.dataset.number);
        }
      }
    }
    // Facebook events, location.
    if (currentURL.hostname.match(/facebook\.com/)) {
      var elements = document.getElementsByTagName('img');
      for(var i=0, len=elements.length; i < len; i++){
        var element = elements[i];
        if (element.src) {
          var re = new RegExp('markers=([0-9\.]+)%2C([0-9\.]+)');
          var matches = element.src.match(re);
          if (matches) {
            var value = 'geo:' + matches[1] + ',' + matches[2];
            addListeners(element, value);
          }
        }
      }
    }
    // Google maps, info sidebar, phone numbers
    if (currentURL.hostname.match(/google/)) {
      var elements = document.getElementsByTagName('button');
      for(var i=0, len=elements.length; i < len; i++){
        var element = elements[i];
        if (element.dataset) {
          if (element.dataset.href) {
            addListeners(element, element.dataset.href);
          }
        }
      }
    }
    // Text selections.
    document.addEventListener('mouseup', handleTextSelect);
  }

  function manualTriggerWithDblClick() {
    window.addEventListener('dblclick', parseAndAddListeners, true);
  }

  function parseURL(url) {
    var parser = document.createElement('a');
    parser.href = url;
    return parser;
  }

  "use strict";

  var currentURL = parseURL(window.location.href);

  // Create code and add to body.
  var i = document.createElement("img");
  i.style.width = "100px";
  i.style.height = "100px";
  i.style.position = "fixed";
  i.style.left = "10px";
  i.style.bottom = "30px";
  i.style.zIndex = "999";
  i.style.visibility = "hidden";
  i.alt = "QR Code";

  document.body.appendChild(i);

  parseAndAddListeners();
  manualTriggerWithDblClick();

}());

<|endoftext|>


<commit_before>'use strict';

//var _ = require('lodash');
var Q = require('q');
var expand = require('glob-expand');

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var $28 = new (require('28').$28)('http://portal.28.io/api');

var Config = require('./config');

var credentials;

var Options = {
    OVERWRITE_ALWAYS: 0,
    OVERWRITE_NEVER: 1,
    OVERWRITE_ASK: 2,
    OVERWRITE_IF_NEWER: 3
};

var throwError = function(error) {
    throw error;
};

var login = function(email, password){
    $.util.log('Logging in as ' + email);
    return $28.login(email, password).then(function(response){
        $.util.log('Logged in.');
        credentials = response.body;
        return credentials;
    });
};

var removeProject = function(projectName, isIdempotent){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Deleting project ' + projectName);
        $28.deleteProject(projectName, token).then(function () {
            $.util.log('Project deleted.');
            defered.resolve(credentials);
        }).catch(function (error) {
            if (!isIdempotent) {
                defered.reject(error);
            } else {
                defered.resolve(credentials);
            }
        });
    } else {
        $.util.log('Skipping project deletion for production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var createProject = function(projectName){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Creating project ' + projectName);
        $28.createProject(projectName, token).then(function (response) {
            $.util.log('Project  ' + projectName + ' created.');
            /*jshint camelcase:false */
            credentials.project_tokens['project_' + projectName] = response.body.projectToken;
            defered.resolve(credentials);
        }).catch(function (error) {
            $.util.log('Project creation failed: ' + error);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping project creation on production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var upload = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Uploading queries.');
    return $28.upload(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, []).then(function(){
        $.util.log('Queries uploaded.');
        return credentials;
    });
};

var runQueries = function(projectName, runQueries) {
    var sequence = [];
    var Queries = $28.api.Queries(projectName);
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    runQueries.forEach(function(queries){
        queries = expand(queries);
        var batch = [];
        queries.forEach(function(query){
            var queryPath = query.substring(Config.paths.queries.length + 1);
            batch.push(function(credentials) {
                /*jshint camelcase:false */
                return Queries.executeQuery({
                    accept: 'application/28.io+json',
                    queryPath: queryPath,
                    format: '',
                    token: projectToken
                }).then(function (data) {
                    $.util.log(('✓ '.green) + queryPath + ' returned with status code: ' + data.response.statusCode);
                    return credentials;
                }).catch(function (error) {
                    $.util.log(error.body);
                    $.util.log(('✗ '.red) + queryPath + ' returned with status code: ' + error.response.statusCode);
                    throw error;
                });
            });
        });

        sequence.push(function(credentials){
            var promises = [];
            batch.forEach(function(unit){
                promises.push(unit(credentials));
            });
            return Q.allSettled(promises).then(function(results){
                results.forEach(function (result) {
                    if (result.state !== 'fulfilled') {
                        throw new Error('Some queries failed.');
                    }
                });
                return credentials;
            });
        });
    });
    return sequence.reduce(Q.when, Q());
};

var createDatasource = function(projectName, datasource){
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        $.util.log('Creating datasource ' + datasource.name);
        var difault = datasource.default ? datasource.default : false;
        /*jshint camelcase:false */
        var projectToken = credentials.project_tokens['project_' + projectName];
        $28.createDatasource(projectName, datasource.category, datasource.name, projectToken, difault, JSON.stringify(datasource.credentials))
        .then(function(){
            $.util.log(datasource.name + ' created');
            defered.resolve(credentials);
        })
        .catch(function (error) {
            $.util.log('datasource creation failed: ' + error);
                defered.reject(error);
        });
    } else {
        $.util.log('Skipping data source creation on production: ' + datasource.name);
        defered.resolve(credentials);
    }
    return defered.promise;
};

gulp.task('28:login', function(){
    return login(Config.credentials['28'].email, Config.credentials['28'].password).catch(throwError);
});

gulp.task('28:create-project', function(){
    return createProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:remove-project', function(){
    return removeProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:upload', function(){
    return upload(Config.projectName).catch(throwError);
});

gulp.task('28:setup-datasource', function(){
    var promises = [];
    Config.credentials['28'].datasources.forEach(function(datasource){
        promises.push(createDatasource(Config.projectName, datasource).catch(throwError));
    });
    return Q.all(promises);
});

gulp.task('28:init', function(){
    return runQueries(Config.projectName, Config.initQueries).catch(throwError);
});

gulp.task('28:test', function(){
    return runQueries(Config.projectName, Config.apiTestQueries).catch(throwError);
});
<commit_msg>Fix test suite<commit_after>'use strict';

//var _ = require('lodash');
var Q = require('q');
var expand = require('glob-expand');

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var $28 = new (require('28').$28)('http://portal.28.io/api');

var Config = require('./config');

var credentials;

var Options = {
    OVERWRITE_ALWAYS: 0,
    OVERWRITE_NEVER: 1,
    OVERWRITE_ASK: 2,
    OVERWRITE_IF_NEWER: 3
};

var throwError = function(error) {
    throw error;
};

var login = function(email, password){
    $.util.log('Logging in as ' + email);
    return $28.login(email, password).then(function(response){
        $.util.log('Logged in.');
        credentials = response.body;
        return credentials;
    });
};

var removeProject = function(projectName, isIdempotent){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Deleting project ' + projectName);
        $28.deleteProject(projectName, token).then(function () {
            $.util.log('Project deleted.');
            defered.resolve(credentials);
        }).catch(function (error) {
            if (!isIdempotent) {
                defered.reject(error);
            } else {
                defered.resolve(credentials);
            }
        });
    } else {
        $.util.log('Skipping project deletion for production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var createProject = function(projectName){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Creating project ' + projectName);
        $28.createProject(projectName, token).then(function (response) {
            $.util.log('Project  ' + projectName + ' created.');
            /*jshint camelcase:false */
            credentials.project_tokens['project_' + projectName] = response.body.projectToken;
            defered.resolve(credentials);
        }).catch(function (error) {
            $.util.log('Project creation failed: ' + error);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping project creation on production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var upload = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Uploading queries.');
    return $28.upload(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, []).then(function(){
        $.util.log('Queries uploaded.');
        return credentials;
    });
};

var runQueries = function(projectName, runQueries) {
    var sequence = [];
    var Queries = $28.api.Queries(projectName);
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    runQueries.forEach(function(queries){
        queries = expand(queries);
        var batch = [];
        queries.forEach(function(query){
            var queryPath = query.substring(Config.paths.queries.length + 1);
            batch.push(function(credentials) {
                /*jshint camelcase:false */
                return Queries.executeQuery({
                    accept: 'application/28.io+json',
                    queryPath: queryPath,
                    format: '',
                    token: projectToken
                }).then(function (data) {
                    $.util.log(('✓ '.green) + queryPath + ' returned with status code: ' + data.response.statusCode);
                    return credentials;
                }).catch(function (error) {
                    $.util.log(error.body);
                    $.util.log(('✗ '.red) + queryPath + ' returned with status code: ' + error.response.statusCode);
                    throw error;
                });
            });
        });

        sequence.push(function(credentials){
            var promises = [];
            batch.forEach(function(unit){
                promises.push(unit(credentials));
            });
            return Q.allSettled(promises).then(function(results){
                results.forEach(function (result) {
                    if (result.state !== 'fulfilled') {
                        throw new Error('Some queries failed.');
                    }
                });
                return credentials;
            });
        });
    });
    return sequence.reduce(Q.when, Q());
};

var createDatasource = function(projectName, datasource){
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        $.util.log('Creating datasource ' + datasource.name);
        var difault = datasource.default ? datasource.default : false;
        /*jshint camelcase:false */
        var projectToken = credentials.project_tokens['project_' + projectName];
        $28.createDatasource(projectName, datasource.category, datasource.name, projectToken, difault, JSON.stringify(datasource.credentials))
        .then(function(){
            $.util.log(datasource.name + ' created');
            defered.resolve(credentials);
        })
        .catch(function (error) {
            $.util.log('datasource creation failed: ' + error);
                defered.reject(error);
        });
    } else {
        $.util.log('Skipping data source creation on production: ' + datasource.name);
        defered.resolve(credentials);
    }
    return defered.promise;
};

gulp.task('28:login', function(){
    return login(Config.credentials['28'].email, Config.credentials['28'].password).catch(throwError);
});

gulp.task('28:create-project', function(){
    return createProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:remove-project', function(){
    return removeProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:upload', function(){
    return upload(Config.projectName).catch(throwError);
});

gulp.task('28:setup-datasource', function(){
    var promises = [];
    Config.credentials['28'].datasources.forEach(function(datasource){
        promises.push(createDatasource(Config.projectName, datasource).catch(throwError));
    });
    return Q.all(promises);
});

gulp.task('28:init', function(){
    return runQueries(Config.projectName, Config.paths.initQueries).catch(throwError);
});

gulp.task('28:test', function(){
    return runQueries(Config.projectName, Config.paths.apiTestQueries).catch(throwError);
});
<|endoftext|>


<commit_before>import supertest from 'supertest';
import dotenv from 'dotenv';
import app from '../index';

dotenv.config();
process.env.NODE_ENV = 'test';

describe('PostIt Tests', () => {
  describe('Authentication routes test', () => {
    it('ensures proper response for successful user sign in', (done) => {

    });
    it('ensures proper response for incorrect auth details', (done) => {

    });
    it('ensures proper response for successful user sign up', (done) => {

    });
    it('ensures proper response for sign up with incorrect data', (done) => {

    });
  });
  describe('Group CRUD operation routes', () => {
    it('ensure proper response when group is created successfully', (done) => {

    });
    it('ensures proper response when messages are posted successfully', (done) => {

    });
    it('ensures all messages for a particular group can be read successfully', (done) => {

    });
    it('ensures all members of a particular group can be read successfully', (done) => {

    });
  });
});
<commit_msg>setup structure of unit tests<commit_after>import supertest from 'supertest';
import dotenv from 'dotenv';
import models from '../models';

dotenv.config();
process.env.NODE_ENV = 'test';

describe('PostIt Tests', () => {
  describe('Database connection tests', () => {
    it('ensures database connection is established', (done) => {
      models.sequelize.authenticate().then((err) => {
        expect(err).toEqual(null);
        done();
      });
    });
  });
  describe('Authentication routes test', () => {
    beforeEach((done) => {
      done();
    });
    it('ensures proper response for successful user sign in', (done) => {
      done();
    });
    it('ensures proper response for incorrect auth details', (done) => {
      done();
    });
  });
  describe('Tests for User creation routes', () => {
    beforeEach((done) => {
      done();
    });
    it('ensures proper response for successful user sign up', (done) => {
      done();
    });
    it('ensures proper response for sign up with incorrect data', (done) => {
      done();
    });
  });
  describe('Tests for Group CRUD operation routes', () => {
    it('ensures successfull group creation', (done) => {
      done();
    });
    it('ensures group can be created with no members added initially', (done) => {
      done();
    });
    it('ensures group can be created with a single member first', (done) => {
      done();
    });
    it('ensures group can be created with multiple members added initially', (done) => {
      done();
    });
    it('ensures successfull posting of messages to groups', (done) => {
      done();
    });
    it('ensures all messages for a particular group can be loaded successfully', (done) => {
      done();
    });
    it('ensures all members of a particular group can be loaded successfully', (done) => {
      done();
    });
    it('ensures all registered users can be loaded from the database', (done) => {
      done();
    });
    it('ensures all groups a user belongs to can be loaded', (done) => {
      done();
    });
  });
  describe('Model tests', () => {
    it('ensures User model is created correctly', (done) => {
      done();
    });
    it('ensures Group model is created successfully', (done) => {
      done();
    });
    it('ensures Message modes is created successfulley', (done) => {
      done();
    });
  });
});
<|endoftext|>


<commit_before>/* =============================================================

	Smooth Scroll v4.5
	Animate scrolling to anchor links, by Chris Ferdinandi.
	http://gomakethings.com

	Additional contributors:
	https://github.com/cferdinandi/smooth-scroll#contributors

	Free to use under the MIT License.
	http://gomakethings.com/mit/

 * ============================================================= */

window.smoothScroll = (function (window, document, undefined) {

	'use strict';

	// Default settings
	// Private {object} variable
	var _defaults = {
		speed: 500,
		easing: 'easeInOutCubic',
		offset: 0,
		updateURL: false,
		callbackBefore: function () {},
		callbackAfter: function () {}
	};

	// Merge default settings with user options
	// Private method
	// Returns an {object}
	var _mergeObjects = function ( original, updates ) {
		for (var key in updates) {
			original[key] = updates[key];
		}
		return original;
	};

	// Calculate the easing pattern
	// Private method
	// Returns a decimal number
	var _easingPattern = function ( type, time ) {
		if ( type == 'easeInQuad' ) return time * time; // accelerating from zero velocity
		if ( type == 'easeOutQuad' ) return time * (2 - time); // decelerating to zero velocity
		if ( type == 'easeInOutQuad' ) return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
		if ( type == 'easeInCubic' ) return time * time * time; // accelerating from zero velocity
		if ( type == 'easeOutCubic' ) return (--time) * time * time + 1; // decelerating to zero velocity
		if ( type == 'easeInOutCubic' ) return time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
		if ( type == 'easeInQuart' ) return time * time * time * time; // accelerating from zero velocity
		if ( type == 'easeOutQuart' ) return 1 - (--time) * time * time * time; // decelerating to zero velocity
		if ( type == 'easeInOutQuart' ) return time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
		if ( type == 'easeInQuint' ) return time * time * time * time * time; // accelerating from zero velocity
		if ( type == 'easeOutQuint' ) return 1 + (--time) * time * time * time * time; // decelerating to zero velocity
		if ( type == 'easeInOutQuint' ) return time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
		return time; // no easing, no acceleration
	};

	// Calculate how far to scroll
	// Private method
	// Returns an integer
	var _getEndLocation = function ( anchor, headerHeight ) {
		var location = 0;
		if (anchor.offsetParent) {
			do {
				location += anchor.offsetTop;
				anchor = anchor.offsetParent;
			} while (anchor);
		}
		location = location - headerHeight;
		if ( location >= 0 ) {
			return location;
		} else {
			return 0;
		}
	};

	// Convert data-options attribute into an object of key/value pairs
	// Private method
	// Returns an {object}
	var _getDataOptions = function ( options ) {

		if ( options === null || options === undefined  ) {
			return {};
		} else {
			var settings = {}; // Create settings object
			options = options.split(';'); // Split into array of options

			// Create a key/value pair for each setting
			options.forEach( function(option) {
				option = option.trim();
				if ( option !== '' ) {
					option = option.split(':');
					settings[option[0]] = option[1].trim();
				}
			});

			return settings;
		}

	};

	// Update the URL
	// Private method
	// Runs functions
	var _updateURL = function ( anchor, url ) {
		if ( (url === true || url === 'true') && history.pushState ) {
			history.pushState( {pos:anchor.id}, '', anchor );
		}
	};

	// Start/stop the scrolling animation
	// Public method
	// Runs functions
	var animateScroll = function ( toggle, anchor, options, event ) {

		// Options and overrides
		options = _mergeObjects( _defaults, options || {} ); // Merge user options with defaults
		var overrides = _getDataOptions( toggle ? toggle.getAttribute('data-options') : null );
		var speed = parseInt(overrides.speed || options.speed, 10);
		var easing = overrides.easing || options.easing;
		var offset = parseInt(overrides.offset || options.offset, 10);
		var updateURL = overrides.updateURL || options.updateURL;

		// Selectors and variables
		var fixedHeader = document.querySelector('[data-scroll-header]'); // Get the fixed header
		var headerHeight = fixedHeader === null ? 0 : (fixedHeader.offsetHeight + fixedHeader.offsetTop); // Get the height of a fixed header if one exists
		var startLocation = window.pageYOffset; // Current location on the page
		var endLocation = _getEndLocation( document.querySelector(anchor), headerHeight + offset ); // Scroll to location
		var animationInterval; // interval timer
		var distance = endLocation - startLocation; // distance to travel
		var timeLapsed = 0;
		var percentage, position;

		// Prevent default click event
		if ( toggle && toggle.tagName === 'A' && event ) {
			event.preventDefault();
		}

		// Update URL
		_updateURL(anchor, updateURL);

		// Stop the scroll animation when it reaches its target (or the bottom/top of page)
		// Private method
		// Runs functions
		var _stopAnimateScroll = function (position, endLocation, animationInterval) {
			var currentLocation = window.pageYOffset;
			if ( position == endLocation || currentLocation == endLocation || ( (window.innerHeight + currentLocation) >= document.body.scrollHeight ) ) {
				clearInterval(animationInterval);
				options.callbackAfter( toggle, anchor ); // Run callbacks after animation complete
			}
		};

		// Loop scrolling animation
		// Private method
		// Runs functions
		var _loopAnimateScroll = function () {
			timeLapsed += 16;
			percentage = ( timeLapsed / speed );
			percentage = ( percentage > 1 ) ? 1 : percentage;
			position = startLocation + ( distance * _easingPattern(easing, percentage) );
			window.scrollTo( 0, Math.floor(position) );
			_stopAnimateScroll(position, endLocation, animationInterval);
		};

		// Set interval timer
		// Private method
		// Runs functions
		var _startAnimateScroll = function () {
			options.callbackBefore( toggle, anchor ); // Run callbacks before animating scroll
			animationInterval = setInterval(_loopAnimateScroll, 16);
		};

		// Reset position to fix weird iOS bug
		// https://github.com/cferdinandi/smooth-scroll/issues/45
		if ( window.pageYOffset === 0 ) {
			window.scrollTo( 0, 0 );
		}

		// Start scrolling animation
		_startAnimateScroll();

	};

	// Initialize Smooth Scroll
	// Public method
	// Runs functions
	var init = function ( options ) {

		// Feature test before initializing
		if ( 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach ) {

			// Selectors and variables
			options = _mergeObjects( _defaults, options || {} ); // Merge user options with defaults
			var toggles = document.querySelectorAll('[data-scroll]'); // Get smooth scroll toggles

			// When a toggle is clicked, run the click handler
			Array.prototype.forEach.call(toggles, function (toggle, index) {
				toggle.addEventListener('click', animateScroll.bind( null, toggle, toggle.getAttribute('href'), options ), false);
			});

		}

	};

	// Return public methods
	return {
		init: init,
		animateScroll: animateScroll
	};

})(window, document);<commit_msg>Fix for issue 49: determining the document's height (cross-browser)<commit_after>/* =============================================================

	Smooth Scroll v4.5
	Animate scrolling to anchor links, by Chris Ferdinandi.
	http://gomakethings.com

	Additional contributors:
	https://github.com/cferdinandi/smooth-scroll#contributors

	Free to use under the MIT License.
	http://gomakethings.com/mit/

 * ============================================================= */

window.smoothScroll = (function (window, document, undefined) {

	'use strict';

	// Default settings
	// Private {object} variable
	var _defaults = {
		speed: 500,
		easing: 'easeInOutCubic',
		offset: 0,
		updateURL: false,
		callbackBefore: function () {},
		callbackAfter: function () {}
	};

	// Merge default settings with user options
	// Private method
	// Returns an {object}
	var _mergeObjects = function ( original, updates ) {
		for (var key in updates) {
			original[key] = updates[key];
		}
		return original;
	};

	// Calculate the easing pattern
	// Private method
	// Returns a decimal number
	var _easingPattern = function ( type, time ) {
		if ( type == 'easeInQuad' ) return time * time; // accelerating from zero velocity
		if ( type == 'easeOutQuad' ) return time * (2 - time); // decelerating to zero velocity
		if ( type == 'easeInOutQuad' ) return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
		if ( type == 'easeInCubic' ) return time * time * time; // accelerating from zero velocity
		if ( type == 'easeOutCubic' ) return (--time) * time * time + 1; // decelerating to zero velocity
		if ( type == 'easeInOutCubic' ) return time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
		if ( type == 'easeInQuart' ) return time * time * time * time; // accelerating from zero velocity
		if ( type == 'easeOutQuart' ) return 1 - (--time) * time * time * time; // decelerating to zero velocity
		if ( type == 'easeInOutQuart' ) return time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
		if ( type == 'easeInQuint' ) return time * time * time * time * time; // accelerating from zero velocity
		if ( type == 'easeOutQuint' ) return 1 + (--time) * time * time * time * time; // decelerating to zero velocity
		if ( type == 'easeInOutQuint' ) return time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
		return time; // no easing, no acceleration
	};

	// Calculate how far to scroll
	// Private method
	// Returns an integer
	var _getEndLocation = function ( anchor, headerHeight ) {
		var location = 0;
		if (anchor.offsetParent) {
			do {
				location += anchor.offsetTop;
				anchor = anchor.offsetParent;
			} while (anchor);
		}
		location = location - headerHeight;
		if ( location >= 0 ) {
			return location;
		} else {
			return 0;
		}
	};

	// Convert data-options attribute into an object of key/value pairs
	// Private method
	// Returns an {object}
	var _getDataOptions = function ( options ) {

		if ( options === null || options === undefined  ) {
			return {};
		} else {
			var settings = {}; // Create settings object
			options = options.split(';'); // Split into array of options

			// Create a key/value pair for each setting
			options.forEach( function(option) {
				option = option.trim();
				if ( option !== '' ) {
					option = option.split(':');
					settings[option[0]] = option[1].trim();
				}
			});

			return settings;
		}

	};

	// Update the URL
	// Private method
	// Runs functions
	var _updateURL = function ( anchor, url ) {
		if ( (url === true || url === 'true') && history.pushState ) {
			history.pushState( {pos:anchor.id}, '', anchor );
		}
	};

    // Determine the document's height (cross-browser)
    // Fix for issue 49 (https://github.com/cferdinandi/smooth-scroll/issues/49)
    // Private method
    var _getDocumentHeight = function () {
        return Math.max(
            document.body.scrollHeight, document.documentElement.scrollHeight,
            document.body.offsetHeight, document.documentElement.offsetHeight,
            document.body.clientHeight, document.documentElement.clientHeight
        );
    };

	// Start/stop the scrolling animation
	// Public method
	// Runs functions
	var animateScroll = function ( toggle, anchor, options, event ) {

		// Options and overrides
		options = _mergeObjects( _defaults, options || {} ); // Merge user options with defaults
		var overrides = _getDataOptions( toggle ? toggle.getAttribute('data-options') : null );
		var speed = parseInt(overrides.speed || options.speed, 10);
		var easing = overrides.easing || options.easing;
		var offset = parseInt(overrides.offset || options.offset, 10);
		var updateURL = overrides.updateURL || options.updateURL;

		// Selectors and variables
		var fixedHeader = document.querySelector('[data-scroll-header]'); // Get the fixed header
		var headerHeight = fixedHeader === null ? 0 : (fixedHeader.offsetHeight + fixedHeader.offsetTop); // Get the height of a fixed header if one exists
		var startLocation = window.pageYOffset; // Current location on the page
		var endLocation = _getEndLocation( document.querySelector(anchor), headerHeight + offset ); // Scroll to location
		var animationInterval; // interval timer
		var distance = endLocation - startLocation; // distance to travel
		var timeLapsed = 0;
		var percentage, position;

		// Prevent default click event
		if ( toggle && toggle.tagName === 'A' && event ) {
			event.preventDefault();
		}

		// Update URL
		_updateURL(anchor, updateURL);

		// Stop the scroll animation when it reaches its target (or the bottom/top of page)
		// Private method
		// Runs functions
		var _stopAnimateScroll = function (position, endLocation, animationInterval) {
			var currentLocation = window.pageYOffset;
			if ( position == endLocation || currentLocation == endLocation || ( (window.innerHeight + currentLocation) >= _getDocumentHeight() ) ) {
				clearInterval(animationInterval);
				options.callbackAfter( toggle, anchor ); // Run callbacks after animation complete
			}
		};

		// Loop scrolling animation
		// Private method
		// Runs functions
		var _loopAnimateScroll = function () {
			timeLapsed += 16;
			percentage = ( timeLapsed / speed );
			percentage = ( percentage > 1 ) ? 1 : percentage;
			position = startLocation + ( distance * _easingPattern(easing, percentage) );
			window.scrollTo( 0, Math.floor(position) );
			_stopAnimateScroll(position, endLocation, animationInterval);
		};

		// Set interval timer
		// Private method
		// Runs functions
		var _startAnimateScroll = function () {
			options.callbackBefore( toggle, anchor ); // Run callbacks before animating scroll
			animationInterval = setInterval(_loopAnimateScroll, 16);
		};

		// Reset position to fix weird iOS bug
		// https://github.com/cferdinandi/smooth-scroll/issues/45
		if ( window.pageYOffset === 0 ) {
			window.scrollTo( 0, 0 );
		}

		// Start scrolling animation
		_startAnimateScroll();

	};

	// Initialize Smooth Scroll
	// Public method
	// Runs functions
	var init = function ( options ) {

		// Feature test before initializing
		if ( 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach ) {

			// Selectors and variables
			options = _mergeObjects( _defaults, options || {} ); // Merge user options with defaults
			var toggles = document.querySelectorAll('[data-scroll]'); // Get smooth scroll toggles

			// When a toggle is clicked, run the click handler
			Array.prototype.forEach.call(toggles, function (toggle, index) {
				toggle.addEventListener('click', animateScroll.bind( null, toggle, toggle.getAttribute('href'), options ), false);
			});

		}

	};

	// Return public methods
	return {
		init: init,
		animateScroll: animateScroll
	};

})(window, document);<|endoftext|>


<commit_before>var assert = require('assert'),
    Persistence = require('../persistence.js'),
    client;

describe('given a connected persistence', function() {

  before(function(done) {
    Persistence.setConfig({ redis_host: 'localhost', redis_port: 6379 });
    Persistence.connect(function() {
      client = Persistence.redis();
      Persistence.delWildCard('*', done);
    });
  });

  after(function(done) {
    Persistence.delWildCard('*', function() {
      Persistence.disconnect(done);
    });
  });

  describe('after connection', function() {
    it('should be able to get client and subscriber', function() {
      assert.ok(Persistence.redis());
      assert.ok(Persistence.pubsub());
    });
  });
  describe('while handling errors', function() {
    it('should filter out non JSON redis strings (ie. do not return corrupted data)', function(done) {

      var key = 'persistence.test';

      client.del(key);
      client.hset(key, 'bar1', 'this string should be filtered out');
      client.hset(key, 'bar2', '"this string should be returned"', function() {
        Persistence.readHashAll(key, function(result) {
          assert.deepEqual({ bar2: 'this string should be returned' }, result);
          done();
        });
      });
    });
  });

  describe('while persisting messages', function() {
    it('should serialize objects', function(done) {
      // (nherment) TODO: the result should actually be deserialized because it is being serialized in persistOrdered()
      // The problem is that radar_client currently deserializes the response.
      // We need to make the client not deserialize the response so that we can deserialize it here.

      var key = 'persistence.messages.object.test';
      var objectValue = {
        foo: 'bar'
      };

      Persistence.persistOrdered(key, objectValue, function(err) {
        if(err) {
          return done(err);
        }
        Persistence.readOrderedWithScores(key, undefined, function(replies) {

          assert(replies instanceof Array);
          assert.equal(2, replies.length);
          assert.equal('string', typeof replies[0]);
          assert.equal(JSON.stringify(objectValue), replies[0]);
          done();
        });
      });
    });

    it('should serialize strings', function(done) {
      // (nherment) TODO: the result should actually be deserialized because it is being serialized in persistOrdered()
      // The problem is that radar_client currently deserializes the response.
      // We need to make the client not deserialize the response so that we can deserialize it here.

      var key = 'persistence.messages.string.test';
      var stringValue = 'Hello World';

      Persistence.persistOrdered(key, stringValue, function(err) {
        if(err) {
          return done(err);
        }
        Persistence.readOrderedWithScores(key, undefined, function(replies) {

          assert(replies instanceof Array);
          assert.equal(2, replies.length);
          assert.equal('string', typeof replies[0]);
          assert.equal(JSON.stringify(stringValue), replies[0]);
          done();
        });
      });
    });
  });

});
<commit_msg>setup our own redis<commit_after>var assert         = require('assert'),
    SentinelHelper = require('simple_sentinel'),
    Persistence    = require('../persistence.js'),
    client;

describe('given a connected persistence', function() {

  before(function(done) {
    process.env.noverbose=true;
    SentinelHelper.start({ redis: { ports: [ 16379 ] } });
    Persistence.setConfig({ redis_host: 'localhost', redis_port: 16379 });
    Persistence.connect(function() {
      client = Persistence.redis();
      Persistence.delWildCard('*', done);
    });
  });

  after(function(done) {
    Persistence.delWildCard('*', function() {
      Persistence.disconnect(function() {
        SentinelHelper.stop({ redis: { ports: [ 16379 ] } });
        done();
      });
    });
  });

  describe('after connection', function() {
    it('should be able to get client and subscriber', function() {
      assert.ok(Persistence.redis());
      assert.ok(Persistence.pubsub());
    });
  });
  describe('while handling errors', function() {
    it('should filter out non JSON redis strings (ie. do not return corrupted data)', function(done) {

      var key = 'persistence.test';

      client.del(key);
      client.hset(key, 'bar1', 'this string should be filtered out');
      client.hset(key, 'bar2', '"this string should be returned"', function() {
        Persistence.readHashAll(key, function(result) {
          assert.deepEqual({ bar2: 'this string should be returned' }, result);
          done();
        });
      });
    });
  });

  describe('while persisting messages', function() {
    it('should serialize objects', function(done) {
      // (nherment) TODO: the result should actually be deserialized because it is being serialized in persistOrdered()
      // The problem is that radar_client currently deserializes the response.
      // We need to make the client not deserialize the response so that we can deserialize it here.

      var key = 'persistence.messages.object.test';
      var objectValue = {
        foo: 'bar'
      };

      Persistence.persistOrdered(key, objectValue, function(err) {
        if(err) {
          return done(err);
        }
        Persistence.readOrderedWithScores(key, undefined, function(replies) {

          assert(replies instanceof Array);
          assert.equal(2, replies.length);
          assert.equal('string', typeof replies[0]);
          assert.equal(JSON.stringify(objectValue), replies[0]);
          done();
        });
      });
    });

    it('should serialize strings', function(done) {
      // (nherment) TODO: the result should actually be deserialized because it is being serialized in persistOrdered()
      // The problem is that radar_client currently deserializes the response.
      // We need to make the client not deserialize the response so that we can deserialize it here.

      var key = 'persistence.messages.string.test';
      var stringValue = 'Hello World';

      Persistence.persistOrdered(key, stringValue, function(err) {
        if(err) {
          return done(err);
        }
        Persistence.readOrderedWithScores(key, undefined, function(replies) {

          assert(replies instanceof Array);
          assert.equal(2, replies.length);
          assert.equal('string', typeof replies[0]);
          assert.equal(JSON.stringify(stringValue), replies[0]);
          done();
        });
      });
    });
  });

});
<|endoftext|>


<commit_before>var WebSocketServer = require('ws').Server,
  resources = require('./../resources/model');

var util = require('util');

exports.listen = function (server) {
  var wss = new WebSocketServer({server: server}); //#A
  console.info('WebSocket server started...');
  wss.on('connection', function (ws) { //#B
    var url = ws.upgradeReq.url;
    try {
      Array.observe(selectResouce(url), function (changes) { //#C
        console.log("Change detected: %s", util.inspect(changes));
        ws.send(JSON.stringify(changes[0].object[changes[0].index]), function () {
        });
      }, ['update'])
    } catch (e) { //#D
      console.log('Unable to observe %s resource!', url);
    };
  });
};

function selectResouce(url) { //#E
  var parts = url.split('/');
  parts.shift();

  var result;
  if (parts[0] === 'actions') {
    result = resources.links.actions.resources[parts[1]].data;
  } else {
    result = resources.links.properties.resources[parts[1]].data;
  }
  return result;
}

//#A Create a WebSocket server by passing it the Express server
//#B Triggered after a protocol upgrade when the client connected
//#C We register an observer corresponding to the resource in the protocol upgrade URL
//#D We use a try/catch to catch to intercept error (e.g., malformed/unsupported URLs)
//#E This function takes a request URL and returns the corresponding resource

<commit_msg>Debugging ws issue on Pi<commit_after>var WebSocketServer = require('ws').Server,
  resources = require('./../resources/model');

var util = require('util');

exports.listen = function (server) {
  var wss = new WebSocketServer({server: server}); //#A
  console.info('WebSocket server started...');
  wss.on('connection', function (ws) { //#B
    var url = ws.upgradeReq.url;
    try {
      Array.observe(selectResouce(url), function (changes) { //#C
        console.log("Change detected: %s", util.inspect(changes));
        ws.send(JSON.stringify(changes[0].object[changes[0].index]), function () {
        });
      }, ['add'])
    } catch (e) { //#D
      console.log('Unable to observe %s resource!', url);
    };
  });
};

function selectResouce(url) { //#E
  var parts = url.split('/');
  parts.shift();

  var result;
  if (parts[0] === 'actions') {
    result = resources.links.actions.resources[parts[1]].data;
  } else {
    result = resources.links.properties.resources[parts[1]].data;
  }
  return result;
}

//#A Create a WebSocket server by passing it the Express server
//#B Triggered after a protocol upgrade when the client connected
//#C We register an observer corresponding to the resource in the protocol upgrade URL
//#D We use a try/catch to catch to intercept error (e.g., malformed/unsupported URLs)
//#E This function takes a request URL and returns the corresponding resource

<|endoftext|>


<commit_before>'use strict';

var test = require("tap").test;
var Raygun = require('../lib/raygun.js');

test('send basic', {}, function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});
    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send complex', {}, function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']}).setUser("callum@mindscape.co.nz").setVersion("1.0.0.0");

    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send with OnBeforeSend', {}, function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    var onBeforeSendCalled = false;
    client.onBeforeSend(function (payload) {
        onBeforeSendCalled = true;
        return payload;
    });

    client.send(new Error(), {}, function () {
        t.equals(onBeforeSendCalled, true);
        t.end();
    });
});

test('send with expressHandler custom data', function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    client.expressCustomData = function () {
        return { 'test': 'data' };
    };
    client._send = client.send;
    client.send = function (err, data) {
        client.send = client._send;
        t.equals(data.test, 'data');
        t.end();
    };
    client.expressHandler(new Error(), {}, {}, function () {});
});

test('check that tags get passed through', {}, function (t) {
    var tag = ['Test'];
    var client = new Raygun.Client().init({apiKey: 'TEST'});

    client.setTags(tag);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, tag);
        t.end();
    });

    client.send(new Error(), {}, function () {
        t.end();
    });
});

test('check that tags get merged', {}, function (t) {
    var client = new Raygun.Client().init({apiKey: 'TEST'});
    client.setTags(['Tag1']);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, ['Tag1', 'Tag2']);
        t.end();
    });

    client.send(new Error(), {}, function () {
        t.end();
    }, null, ["Tag2"]);
});<commit_msg>Don't end functional sending tests in target callbacks<commit_after>'use strict';

var test = require("tap").test;
var Raygun = require('../lib/raygun.js');

test('send basic', {}, function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});
    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send complex', {}, function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']}).setUser("callum@mindscape.co.nz").setVersion("1.0.0.0");

    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send with OnBeforeSend', {}, function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    var onBeforeSendCalled = false;
    client.onBeforeSend(function (payload) {
        onBeforeSendCalled = true;
        return payload;
    });

    client.send(new Error(), {}, function () {
        t.equals(onBeforeSendCalled, true);
        t.end();
    });
});

test('send with expressHandler custom data', function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    client.expressCustomData = function () {
        return { 'test': 'data' };
    };
    client._send = client.send;
    client.send = function (err, data) {
        client.send = client._send;
        t.equals(data.test, 'data');
        t.end();
    };
    client.expressHandler(new Error(), {}, {}, function () {});
});

test('check that tags get passed through', {}, function (t) {
    var tag = ['Test'];
    var client = new Raygun.Client().init({apiKey: 'TEST'});

    client.setTags(tag);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, tag);
    });

    client.send(new Error(), {}, function () {
        t.end();
    });
});

test('check that tags get merged', {}, function (t) {
    var client = new Raygun.Client().init({apiKey: 'TEST'});
    client.setTags(['Tag1']);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, ['Tag1', 'Tag2']);
    });

    client.send(new Error(), {}, function () {
        t.end();
    }, null, ["Tag2"]);
});<|endoftext|>


<commit_before>'use strict';

var test = require("tap").test;
var semver = require('semver');
var Raygun = require('../lib/raygun.js');

test('send basic', {}, function (t) {
    t.plan(1);

    if (semver.satisfies(process.version, '=0.10')) {
      t.end();
      return;
    }

    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});
    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send complex', {}, function (t) {
    t.plan(1);

    if (semver.satisfies(process.version, '=0.10')) {
      t.end();
      return;
    }

    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']}).setUser("callum@mindscape.co.nz").setVersion("1.0.0.0");

    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send with OnBeforeSend', {}, function (t) {
    t.plan(1);

    if (semver.satisfies(process.version, '=0.10')) {
      t.end();
      return;
    }

    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    var onBeforeSendCalled = false;
    client.onBeforeSend(function (payload) {
        onBeforeSendCalled = true;
        return payload;
    });

    client.send(new Error(), {}, function () {
        t.equals(onBeforeSendCalled, true);
        t.end();
    });
});

test('send with expressHandler custom data', function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    client.expressCustomData = function () {
        return { 'test': 'data' };
    };
    client._send = client.send;
    client.send = function (err, data) {
        client.send = client._send;
        t.equals(data.test, 'data');
        t.end();
    };
    client.expressHandler(new Error(), {}, {}, function () {});
});

test('check that tags get passed through', {}, function (t) {
    var tag = ['Test'];
    var client = new Raygun.Client().init({apiKey: 'TEST'});

    client.setTags(tag);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, tag);
        t.end();
    });

    client.send(new Error(), {}, function () {
        t.end();
    });
});

test('check that tags get merged', {}, function (t) {
    var client = new Raygun.Client().init({apiKey: 'TEST'});
    client.setTags(['Tag1']);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, ['Tag1', 'Tag2']);
        t.end();
    });

    client.send(new Error(), {}, function () {
        t.end();
    }, null, ["Tag2"]);
});<commit_msg>Need to specifically pass ignored tests<commit_after>'use strict';

var test = require("tap").test;
var semver = require('semver');
var Raygun = require('../lib/raygun.js');

test('send basic', {}, function (t) {
    t.plan(1);

    if (semver.satisfies(process.version, '=0.10')) {
      t.pass('Ignored on node 0.10');
      t.end();
      return;
    }

    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});
    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send complex', {}, function (t) {
    t.plan(1);

    if (semver.satisfies(process.version, '=0.10')) {
      t.pass('Ignored on node 0.10');
      t.end();
      return;
    }

    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']}).setUser("callum@mindscape.co.nz").setVersion("1.0.0.0");

    client.send(new Error(), {}, function (response) {
        t.equals(response.statusCode, 202);
        t.end();
    });
});

test('send with OnBeforeSend', {}, function (t) {
    t.plan(1);

    if (semver.satisfies(process.version, '=0.10')) {
      t.pass('Ignored on node 0.10');
      t.end();
      return;
    }

    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    var onBeforeSendCalled = false;
    client.onBeforeSend(function (payload) {
        onBeforeSendCalled = true;
        return payload;
    });

    client.send(new Error(), {}, function () {
        t.equals(onBeforeSendCalled, true);
        t.end();
    });
});

test('send with expressHandler custom data', function (t) {
    t.plan(1);
    var client = new Raygun.Client().init({apiKey: process.env['RAYGUN_APIKEY']});

    client.expressCustomData = function () {
        return { 'test': 'data' };
    };
    client._send = client.send;
    client.send = function (err, data) {
        client.send = client._send;
        t.equals(data.test, 'data');
        t.end();
    };
    client.expressHandler(new Error(), {}, {}, function () {});
});

test('check that tags get passed through', {}, function (t) {
    var tag = ['Test'];
    var client = new Raygun.Client().init({apiKey: 'TEST'});

    client.setTags(tag);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, tag);
        t.end();
    });

    client.send(new Error(), {}, function () {
        t.end();
    });
});

test('check that tags get merged', {}, function (t) {
    var client = new Raygun.Client().init({apiKey: 'TEST'});
    client.setTags(['Tag1']);

    client.onBeforeSend(function (payload) {
        t.same(payload.details.tags, ['Tag1', 'Tag2']);
        t.end();
    });

    client.send(new Error(), {}, function () {
        t.end();
    }, null, ["Tag2"]);
});<|endoftext|>


<commit_before>const fs = require('fs');
const program = require('commander');
const packageJson = require('../package.json');

// const BOOTSTRAP_TYPE_CLIENT = 0;
const BOOTSTRAP_TYPE_SERVER = 1;

const version = packageJson.version;
const usage = '--host <host> --port <port> --key <key> [...]';

const options = [
  ['-c, --config [file]', 'a json format file for configuration', ''],
  ['--host <host>', 'an ip address or a hostname to bind, default: \'localhost\'', 'localhost'],
  ['--port <port>', 'where to listen on, default: 1080', 1080],
  ['--servers [servers]', 'a list of servers used by client, split by comma, default: \'\'', (value) => value.split(','), []],
  ['--key <key>', 'a key for encryption and decryption'],
  ['--frame [frame]', 'a preset used in frame middleware, default: \'origin\'', 'origin'],
  ['--frame-params [crypto-params]', 'parameters for frame preset, default: \'\'', ''],
  ['--crypto [crypto]', 'a preset used in crypto middleware, default: \'\'', ''],
  ['--crypto-params [crypto-params]', 'parameters for crypto, default: \'aes-256-cfb\'', 'aes-256-cfb'],
  ['--protocol [protocol]', 'a preset used in protocol middleware, default: \'aead\'', 'aead'],
  ['--protocol-params [protocol-params]', 'parameters for protocol, default: \'aes-256-gcm,ss-subkey\'', 'aes-256-gcm,ss-subkey'],
  ['--obfs [obfs]', 'a preset used in obfs middleware, default: \'\'', ''],
  ['--obfs-params [obfs-params]', 'parameters for obfs, default: \'\'', ''],
  ['--redirect [redirect]', 'redirect stream to here when any preset fail to process, default: \'\'', ''],
  ['--log-level [log-level]', 'log level, default: \'silly\'', 'silly'],
  ['--timeout [timeout]', 'time to close connection if inactive, default: 600', 600],
  ['-q, --quiet [quiet]', 'force log level to \'error\', default: false', false],
  ['-w, --watch [watch]', 'hot reload config.json specified via -c, default: true', true],
  ['--profile [profile]', 'generate performance statistics, store at blinksocks.profile.log once exit, default: false', false]
];

const examples = `
  Examples:

  As simple as possible:
    $ blinksocks client -c config.json --watch

  To start a server:
    $ blinksocks server --host 0.0.0.0 --port 7777 --key password

  To start a client:
    $ blinksocks client --host localhost --port 1080 --key password --servers=node1.test.com:7777,node2.test.com:7777
`;

/**
 * get raw config object from json or command line options
 * @param type, BOOTSTRAP_TYPE_CLIENT or BOOTSTRAP_TYPE_SERVER
 * @param options
 * @returns {object}
 */
function obtainConfig(type, options) {
  // CLI options should be able to overwrite options specified in --config
  const {host, servers, key, quiet} = options;
  const {frame, crypto, protocol, obfs, redirect} = options;

  // renames
  const [frame_params, crypto_params, protocol_params, obfs_params] = [
    options.frameParams,
    options.cryptoParams,
    options.protocolParams,
    options.obfsParams
  ];

  // pre-process
  const [port, log_level, timeout, watch, profile] = [
    parseInt(options.port, 10),
    quiet ? 'error' : options.logLevel,
    parseInt(options.timeout, 10),
    !!options.watch,
    !!options.profile
  ];

  // assemble, undefined fields will be omitted
  const config = {
    host,
    port,
    servers,
    key,
    frame,
    frame_params,
    crypto,
    crypto_params,
    protocol,
    protocol_params,
    obfs,
    obfs_params,
    redirect,
    log_level,
    timeout,
    watch,
    profile
  };

  // --config, if provided, options in config.json should be able to overwrite CLI options
  if (options.config !== '') {
    const file = options.config;
    try {
      const jsonFile = fs.readFileSync(file);
      Object.assign(config, JSON.parse(jsonFile));
    } catch (err) {
      throw Error(`error parse your \'${file}\'`);
    }
  }

  /// post-process
  if (type === BOOTSTRAP_TYPE_SERVER) {
    delete config.servers;
  } else {
    config.servers = config.servers.filter((server) => server[0] !== '-');
  }
  return config;
}

module.exports = function (type, {Hub, Config}) {
  const pg = program.version(version).usage(usage);

  for (const option of options) {
    pg.option(...option);
  }

  program.on('--help', () => console.log(examples));
  program.parse(process.argv);

  // no options provided
  if (process.argv.length < 3) {
    program.help();
    process.exit(0);
  }

  if (program.config !== '' && program.watch) {
    fs.watchFile(program.config, function (curr, prev) {
      if (curr.mtime > prev.mtime) {
        console.log(`==> [bootstrap] ${program.config} has changed, reload`);
        try {
          Config.init(obtainConfig(type, program));
          console.info(JSON.stringify(Config.abstract(), null, '  '));
        } catch (err) {
          console.error(err.message);
        }
      }
    });
  }

  try {
    Config.init(obtainConfig(type, program));
    const app = new Hub();
    app.run();
    process.on('SIGINT', () => app.onClose());
  } catch (err) {
    console.error(err.message);
    process.exit(-1);
  }
};
<commit_msg>feat(bootstrap): support configuration file with ".js" format<commit_after>const fs = require('fs');
const path = require('path');
const program = require('commander');
const packageJson = require('../package.json');

// const BOOTSTRAP_TYPE_CLIENT = 0;
const BOOTSTRAP_TYPE_SERVER = 1;

const version = packageJson.version;
const usage = '--host <host> --port <port> --key <key> [...]';

const options = [
  ['-c, --config [file]', 'a json format file for configuration', ''],
  ['--host <host>', 'an ip address or a hostname to bind, default: \'localhost\'', 'localhost'],
  ['--port <port>', 'where to listen on, default: 1080', 1080],
  ['--servers [servers]', 'a list of servers used by client, split by comma, default: \'\'', (value) => value.split(','), []],
  ['--key <key>', 'a key for encryption and decryption'],
  ['--frame [frame]', 'a preset used in frame middleware, default: \'origin\'', 'origin'],
  ['--frame-params [crypto-params]', 'parameters for frame preset, default: \'\'', ''],
  ['--crypto [crypto]', 'a preset used in crypto middleware, default: \'\'', ''],
  ['--crypto-params [crypto-params]', 'parameters for crypto, default: \'aes-256-cfb\'', 'aes-256-cfb'],
  ['--protocol [protocol]', 'a preset used in protocol middleware, default: \'aead\'', 'aead'],
  ['--protocol-params [protocol-params]', 'parameters for protocol, default: \'aes-256-gcm,ss-subkey\'', 'aes-256-gcm,ss-subkey'],
  ['--obfs [obfs]', 'a preset used in obfs middleware, default: \'\'', ''],
  ['--obfs-params [obfs-params]', 'parameters for obfs, default: \'\'', ''],
  ['--redirect [redirect]', 'redirect stream to here when any preset fail to process, default: \'\'', ''],
  ['--log-level [log-level]', 'log level, default: \'silly\'', 'silly'],
  ['--timeout [timeout]', 'time to close connection if inactive, default: 600', 600],
  ['-q, --quiet [quiet]', 'force log level to \'error\', default: false', false],
  ['-w, --watch [watch]', 'hot reload config.json specified via -c, default: true', true],
  ['--profile [profile]', 'generate performance statistics, store at blinksocks.profile.log once exit, default: false', false]
];

const examples = `
  Examples:

  As simple as possible:
    $ blinksocks client -c config.json --watch

  To start a server:
    $ blinksocks server --host 0.0.0.0 --port 7777 --key password

  To start a client:
    $ blinksocks client --host localhost --port 1080 --key password --servers=node1.test.com:7777,node2.test.com:7777
`;

/**
 * get raw config object from json or command line options
 * @param type, BOOTSTRAP_TYPE_CLIENT or BOOTSTRAP_TYPE_SERVER
 * @param options
 * @returns {object}
 */
function obtainConfig(type, options) {
  // CLI options should be able to overwrite options specified in --config
  const {host, servers, key, quiet} = options;
  const {frame, crypto, protocol, obfs, redirect} = options;

  // renames
  const [frame_params, crypto_params, protocol_params, obfs_params] = [
    options.frameParams,
    options.cryptoParams,
    options.protocolParams,
    options.obfsParams
  ];

  // pre-process
  const [port, log_level, timeout, watch, profile] = [
    parseInt(options.port, 10),
    quiet ? 'error' : options.logLevel,
    parseInt(options.timeout, 10),
    !!options.watch,
    !!options.profile
  ];

  // assemble, undefined fields will be omitted
  const config = {
    host,
    port,
    servers,
    key,
    frame,
    frame_params,
    crypto,
    crypto_params,
    protocol,
    protocol_params,
    obfs,
    obfs_params,
    redirect,
    log_level,
    timeout,
    watch,
    profile
  };

  // --config, if provided, options in config.json should be able to overwrite CLI options
  if (options.config !== '') {
    // resolve to absolute path
    const file = path.resolve(process.cwd(), options.config);
    try {
      let json;
      const ext = path.extname(file);
      if (ext === '.js') {
        // require .js directly
        json = require(file);
      } else {
        // others are treated as .json
        const jsonFile = fs.readFileSync(file);
        json = JSON.parse(jsonFile);
      }
      Object.assign(config, json);
    } catch (err) {
      throw Error(`fail to parse your \'${options.config}\'`);
    }
  }

  /// post-process
  if (type === BOOTSTRAP_TYPE_SERVER) {
    delete config.servers;
  } else {
    config.servers = config.servers.filter((server) => server[0] !== '-');
  }
  return config;
}

module.exports = function (type, {Hub, Config}) {
  const pg = program.version(version).usage(usage);

  for (const option of options) {
    pg.option(...option);
  }

  program.on('--help', () => console.log(examples));
  program.parse(process.argv);

  // no options provided
  if (process.argv.length < 3) {
    program.help();
    process.exit(0);
  }

  if (program.config !== '' && program.watch) {
    fs.watchFile(program.config, function (curr, prev) {
      if (curr.mtime > prev.mtime) {
        console.log(`==> [bootstrap] ${program.config} has changed, reload`);
        try {
          Config.init(obtainConfig(type, program));
          console.info(JSON.stringify(Config.abstract(), null, '  '));
        } catch (err) {
          console.error(err.message);
        }
      }
    });
  }

  try {
    Config.init(obtainConfig(type, program));
    const app = new Hub();
    app.run();
    process.on('SIGINT', () => app.onClose());
  } catch (err) {
    console.error(err.message);
    process.exit(-1);
  }
};
<|endoftext|>


<commit_before>const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const bundleOutputDir = './wwwroot/dist';

module.exports = (env) => {
    const isDevBuild = !(env && env.prod);
    return [{
        stats: { modules: false },
        entry: {
            'root': './Client/root.tsx',
            'order': './Client/order.tsx',
            'boot': './Client/boot.tsx',
            'react': ['react', 'react-dom', 'react-router', 'react-toolbox']
        },
        resolve: { extensions: [ '.js', '.jsx', '.ts', '.tsx' ] },
        output: {
            path: path.join(__dirname, bundleOutputDir),
            filename: '[name].js',
            publicPath: '/dist/'
        },
        module: {
            rules: [
                { test: /\.ts(x?)$/, include: /Client/, use: 'babel-loader' },
                { test: /\.tsx?$/, include: /Client/, use: 'awesome-typescript-loader?silent=true' },
                { test: /\.css$/, use: isDevBuild ? ['style-loader', { loader: 'css-loader', options: { modules: true, importLoaders: 1, localIdentName: '[name]__[local]___[hash:base64:5]', sourceMap: true }}, 'postcss-loader'] : ExtractTextPlugin.extract({ use: 'css-loader' }) },
                { test: /\.scss$/, use: isDevBuild ? ['style-loader', { loader: 'css-loader', options: { modules: true, importLoaders: 1 }}, 'sass-loader'] : ExtractTextPlugin.extract({ use: ['css-loader', 'sass-loader'] }) },
                { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
            ]
        },
        plugins: [
            new CheckerPlugin(),
            new webpack.optimize.CommonsChunkPlugin({
                name: 'react',
                chunks: ['boot']
            })
        ].concat(isDevBuild ? [
            // Plugins that apply in development builds only
            new webpack.SourceMapDevToolPlugin({
                filename: '[file].map', // Remove this line if you prefer inline source maps
                moduleFilenameTemplate: path.relative(bundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
            })
        ] : [
            // Plugins that apply in production builds only
            new webpack.optimize.UglifyJsPlugin(),
            new ExtractTextPlugin('site.css')
        ])
    }];
};
<commit_msg>load modules in prod<commit_after>const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const bundleOutputDir = './wwwroot/dist';

module.exports = (env) => {
    const isDevBuild = !(env && env.prod);
    const cssLoader = {
        loader: 'css-loader',
        options: {
            modules: true,
            importLoaders: 1,
            localIdentName: '[name]__[local]___[hash:base64:5]',
            sourceMap: true
        }
    };
    return [{
        stats: { modules: false },
        entry: {
            'root': './Client/root.tsx',
            'order': './Client/order.tsx',
            'boot': './Client/boot.tsx',
            'react': ['react', 'react-dom', 'react-router', 'react-toolbox']
        },
        resolve: { extensions: [ '.js', '.jsx', '.ts', '.tsx' ] },
        output: {
            path: path.join(__dirname, bundleOutputDir),
            filename: '[name].js',
            publicPath: '/dist/'
        },
        module: {
            rules: [
                { test: /\.ts(x?)$/, include: /Client/, use: 'babel-loader' },
                { test: /\.tsx?$/, include: /Client/, use: 'awesome-typescript-loader?silent=true' },
                { test: /\.css$/, use: isDevBuild ? ['style-loader', cssLoader, 'postcss-loader'] : ExtractTextPlugin.extract({ use: cssLoader }) },
                { test: /\.scss$/, use: isDevBuild ? ['style-loader', 'css-loader', 'sass-loader'] : ExtractTextPlugin.extract({ use: ['css-loader', 'sass-loader'] }) },
                { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
            ]
        },
        plugins: [
            new CheckerPlugin(),
            new webpack.optimize.CommonsChunkPlugin({
                name: 'react',
                chunks: ['boot']
            })
        ].concat(isDevBuild ? [
            // Plugins that apply in development builds only
            new webpack.SourceMapDevToolPlugin({
                filename: '[file].map', // Remove this line if you prefer inline source maps
                moduleFilenameTemplate: path.relative(bundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
            })
        ] : [
            // Plugins that apply in production builds only
            new webpack.optimize.UglifyJsPlugin(),
            new ExtractTextPlugin('site.css')
        ])
    }];
};
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

var _ = require('lodash');
var Q = require('q');
var AWS = require('aws-sdk');
var parallelize = require('concurrent-transform');

var Config = require('./config');

var s3, key, secret, region, config, publisher, bucketName;

var init = function() {
    key = Config.credentials.s3.key;
    secret = Config.credentials.s3.secret;
    region = Config.credentials.s3.region;
    bucketName = Config.bucketName;
    $.util.log('Bucket Name: ' + bucketName);
    config = {
        accessKeyId: key,
        secretAccessKey: secret,
        region: region,
        bucket: bucketName
    };
    publisher = $.awspublish.create({
        key: key,
        secret: secret,
        bucket: bucketName
    });
    s3 = new AWS.S3(config);
};

var checkWebsiteAvailable = function(){
    var defered = Q.defer();
    var url = 'http://' + bucketName + '.s3-website-' + region + '.amazonaws.com/index.html';
    var request = require('request');
    request({
        uri: url,
        method: 'GET'
    }, function(error, response){
        if(!error && response.statusCode === 200){
            $.util.log('Website available at: ' + $.util.colors.green(url));
            defered.resolve();
        } else {
            if(error){
                $.util.log('checkWebsiteAvailable(' + url + '): ' + $.util.colors.red(error));
            } else {
                $.util.log('checkWebsiteAvailable(' + url + ') status: ' + $.util.colors.red(response.statusCode));
            }
            defered.reject();
        }
    });
    return defered.promise;
};

var makeBucketWebsite = function() {
    var defered = Q.defer();
    s3.putBucketWebsite(
        {
            Bucket : bucketName,
            WebsiteConfiguration : Config.credentials.s3.website
        }, function(err) {
            if (err) {
                $.util.log('putBucketWebsite(' + bucketName + '): ' + $.util.colors.red(err));
                defered.reject();
            }
            else {
                $.util.log('putBucketWebsite(' + bucketName + ')');
                defered.resolve();
            }
        }
    );
    return defered.promise;
};

// Will list *all* the content of the bucket given in options
// Recursively requests the bucket with a marker if there's more than
// 1000 objects. Ensures uniqueness of keys in the returned list.
var listObjects = function (idempotent, prefix, marker, contents) {
    var defered = Q.defer();

    var search = {
        Prefix: prefix,
        Bucket: bucketName
    };

    if (marker) {
        search.Marker = marker;
    }

    s3.listObjects(search, function (err, list) {
        if (!err) {
            var objects = (contents) ? contents.concat(list.Contents) : list.Contents;

            if (list.IsTruncated) {
                var newMarker = _.last(list.Contents).Key;
                listObjects(idempotent, prefix, newMarker, objects);
            } else {
                defered.resolve(_.uniq(objects, function (o) { return o.Key; }));
            }
        } else {
            if(idempotent) {
                defered.resolve();
            } else {
                defered.reject(new Error('Failed to list content of bucket ' + bucketName + '\n' + $.util.colors.red(err)));
            }
        }
    });
    return defered.promise;
};

var waitForBucketExists = function() {
    var defered = Q.defer();
    s3.waitFor('bucketExists', {
        Bucket : bucketName
    }, function(err) {
        if (err) {
            $.util.log($.util.colors.red(bucketName + err), err.stack);
            defered.reject();
        } else {
            $.util.log('waitFor(bucketExists, ' + bucketName + ')');
            defered.resolve();
        }
    });
    return defered.promise;
};

var createBucket = function() {
    var defered = Q.defer();
    s3.createBucket({
        Bucket : bucketName,
        ACL : 'public-read'
    }, function(err, data) {
        if (err || data === null) {
            $.util.log($.util.colors.red(bucketName + err));
            defered.reject();
        } else {
            $.util.log('createBucket(' + bucketName + ')');
            defered.resolve();
        }
    });
    return defered.promise;
};

var deleteBucket = function(idempotent) {
    return listObjects(idempotent)
        .then(function(list){
            $.util.log('listObjects(' + bucketName + ')');
            if(list && list.length > 0) {
                var deleteList = [];
                list.forEach(function(object){
                    deleteList.push({
                        Key: object.Key,
                        VersionId: object.VersionId
                    });
                });
                var defered = Q.defer();
                s3.deleteObjects({
                    Bucket: bucketName,
                    Delete: {
                        Objects: deleteList
                    }
                }, function(err, data){
                    if (err || data === null) {
                        $.util.log('deleteObjects(' + bucketName + '): ' + err);
                        defered.reject();
                    } else {
                        $.util.log('deleteObjects(' + bucketName + ')');
                        defered.resolve();
                    }
                });
                return defered.promise;
            }
        })
        .fin(function(){
            var defered = Q.defer();
            s3.deleteBucket({
                Bucket : bucketName
            }, function(err, data) {
                if ((err || data === null) && !idempotent) {
                    $.util.log('deleteBucket(' + bucketName + '): ' + err);
                    defered.reject();
                } else {
                    $.util.log('deleteBucket(' + bucketName + ')');
                    defered.resolve();
                }
            });
            return defered.promise;
        });
};

gulp.task('s3-setup', function() {
    var idempotent = true;
    init();
    if(!Config.isOnProduction) {
        return deleteBucket(idempotent)
        .then(createBucket)
        .then(waitForBucketExists)
        .then(makeBucketWebsite)
        .then(function(){
            var defered = Q.defer();
            gulp.src('dist/**/*')
                    .pipe($.awspublish.gzip())
                    .pipe(parallelize(publisher.publish(), 10))
                    .pipe($.awspublish.reporter())
                    .on('error', defered.reject)
                    .on('end', defered.resolve);
            return defered.promise;
        })
        .then(checkWebsiteAvailable)
        .catch(function(error){
            $.util.log($.util.colors.red('Error while doing the s3 setup'));
            $.util.log(error);
            throw new $.util.PluginError(__filename, JSON.stringify(error));
        });
    } else {
        return gulp.src('dist/**/*')
            .pipe($.awspublish.gzip())
            .pipe(parallelize(publisher.publish(), 10))
            .pipe($.awspublish.reporter());
    }
});

gulp.task('s3-teardown', function(done) {
    init();
    if(!Config.isOnProduction) {
        deleteBucket().then(function(){
            done();
        })
        .catch(function(error){
            $.util.log('Error while doing the s3 setup');
            $.util.log(error);
            done(JSON.stringify(error));
        });
    } else {
        $.util.log('We are on master, no teardown.');
        done();
    }
});
<commit_msg>:lipstick: Improved log url<commit_after>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

var _ = require('lodash');
var Q = require('q');
var AWS = require('aws-sdk');
var parallelize = require('concurrent-transform');

var Config = require('./config');

var s3, key, secret, region, config, publisher, bucketName;

var init = function() {
    key = Config.credentials.s3.key;
    secret = Config.credentials.s3.secret;
    region = Config.credentials.s3.region;
    bucketName = Config.bucketName;
    $.util.log('Bucket Name: ' + bucketName);
    config = {
        accessKeyId: key,
        secretAccessKey: secret,
        region: region,
        bucket: bucketName
    };
    publisher = $.awspublish.create({
        key: key,
        secret: secret,
        bucket: bucketName
    });
    s3 = new AWS.S3(config);
};

var checkWebsiteAvailable = function(){
    var defered = Q.defer();
    var url = 'http://' + bucketName + '.s3-website-' + region + '.amazonaws.com';
    var request = require('request');
    request({
        uri: url,
        method: 'GET'
    }, function(error, response){
        if(!error && response.statusCode === 200){
            $.util.log('Website available at: ' + $.util.colors.green(url));
            defered.resolve();
        } else {
            if(error){
                $.util.log('checkWebsiteAvailable(' + url + '): ' + $.util.colors.red(error));
            } else {
                $.util.log('checkWebsiteAvailable(' + url + ') status: ' + $.util.colors.red(response.statusCode));
            }
            defered.reject();
        }
    });
    return defered.promise;
};

var makeBucketWebsite = function() {
    var defered = Q.defer();
    s3.putBucketWebsite(
        {
            Bucket : bucketName,
            WebsiteConfiguration : Config.credentials.s3.website
        }, function(err) {
            if (err) {
                $.util.log('putBucketWebsite(' + bucketName + '): ' + $.util.colors.red(err));
                defered.reject();
            }
            else {
                $.util.log('putBucketWebsite(' + bucketName + ')');
                defered.resolve();
            }
        }
    );
    return defered.promise;
};

// Will list *all* the content of the bucket given in options
// Recursively requests the bucket with a marker if there's more than
// 1000 objects. Ensures uniqueness of keys in the returned list.
var listObjects = function (idempotent, prefix, marker, contents) {
    var defered = Q.defer();

    var search = {
        Prefix: prefix,
        Bucket: bucketName
    };

    if (marker) {
        search.Marker = marker;
    }

    s3.listObjects(search, function (err, list) {
        if (!err) {
            var objects = (contents) ? contents.concat(list.Contents) : list.Contents;

            if (list.IsTruncated) {
                var newMarker = _.last(list.Contents).Key;
                listObjects(idempotent, prefix, newMarker, objects);
            } else {
                defered.resolve(_.uniq(objects, function (o) { return o.Key; }));
            }
        } else {
            if(idempotent) {
                defered.resolve();
            } else {
                defered.reject(new Error('Failed to list content of bucket ' + bucketName + '\n' + $.util.colors.red(err)));
            }
        }
    });
    return defered.promise;
};

var waitForBucketExists = function() {
    var defered = Q.defer();
    s3.waitFor('bucketExists', {
        Bucket : bucketName
    }, function(err) {
        if (err) {
            $.util.log($.util.colors.red(bucketName + err), err.stack);
            defered.reject();
        } else {
            $.util.log('waitFor(bucketExists, ' + bucketName + ')');
            defered.resolve();
        }
    });
    return defered.promise;
};

var createBucket = function() {
    var defered = Q.defer();
    s3.createBucket({
        Bucket : bucketName,
        ACL : 'public-read'
    }, function(err, data) {
        if (err || data === null) {
            $.util.log($.util.colors.red(bucketName + err));
            defered.reject();
        } else {
            $.util.log('createBucket(' + bucketName + ')');
            defered.resolve();
        }
    });
    return defered.promise;
};

var deleteBucket = function(idempotent) {
    return listObjects(idempotent)
        .then(function(list){
            $.util.log('listObjects(' + bucketName + ')');
            if(list && list.length > 0) {
                var deleteList = [];
                list.forEach(function(object){
                    deleteList.push({
                        Key: object.Key,
                        VersionId: object.VersionId
                    });
                });
                var defered = Q.defer();
                s3.deleteObjects({
                    Bucket: bucketName,
                    Delete: {
                        Objects: deleteList
                    }
                }, function(err, data){
                    if (err || data === null) {
                        $.util.log('deleteObjects(' + bucketName + '): ' + err);
                        defered.reject();
                    } else {
                        $.util.log('deleteObjects(' + bucketName + ')');
                        defered.resolve();
                    }
                });
                return defered.promise;
            }
        })
        .fin(function(){
            var defered = Q.defer();
            s3.deleteBucket({
                Bucket : bucketName
            }, function(err, data) {
                if ((err || data === null) && !idempotent) {
                    $.util.log('deleteBucket(' + bucketName + '): ' + err);
                    defered.reject();
                } else {
                    $.util.log('deleteBucket(' + bucketName + ')');
                    defered.resolve();
                }
            });
            return defered.promise;
        });
};

gulp.task('s3-setup', function() {
    var idempotent = true;
    init();
    if(!Config.isOnProduction) {
        return deleteBucket(idempotent)
        .then(createBucket)
        .then(waitForBucketExists)
        .then(makeBucketWebsite)
        .then(function(){
            var defered = Q.defer();
            gulp.src('dist/**/*')
                    .pipe($.awspublish.gzip())
                    .pipe(parallelize(publisher.publish(), 10))
                    .pipe($.awspublish.reporter())
                    .on('error', defered.reject)
                    .on('end', defered.resolve);
            return defered.promise;
        })
        .then(checkWebsiteAvailable)
        .catch(function(error){
            $.util.log($.util.colors.red('Error while doing the s3 setup'));
            $.util.log(error);
            throw new $.util.PluginError(__filename, JSON.stringify(error));
        });
    } else {
        return gulp.src('dist/**/*')
            .pipe($.awspublish.gzip())
            .pipe(parallelize(publisher.publish(), 10))
            .pipe($.awspublish.reporter());
    }
});

gulp.task('s3-teardown', function(done) {
    init();
    if(!Config.isOnProduction) {
        deleteBucket().then(function(){
            done();
        })
        .catch(function(error){
            $.util.log('Error while doing the s3 setup');
            $.util.log(error);
            done(JSON.stringify(error));
        });
    } else {
        $.util.log('We are on master, no teardown.');
        done();
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 prussian <genunrest@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var fs = require('fs'),
    path = require('path'),
    mkdirp = require('mkdirp'),
    waterfall = require('async.waterfall')

module.exports = (tree, cb) => {
    var template, rstream
    try {
        template = require(
            path.join(__dirname, 'templates', tree.source)
        )(tree.variables)
    }
    catch (err) {
        return cb(err, {
            status: 'failed to template, may be a syntax error',
            exception: err
        })
    }

    rstream.push(template)

    waterfall([(next) => {
        if (!tree.mkdir) return next()
        mkdirp(path.dirname(tree.destination), next)
    }, (next) => {
        var fpipe
        fpipe = fs.createWriteStream(
            tree.destination,
            { mode: parseInt(tree.mode, 8) }
        ).write(template)
        fpipe.on('error', next)
        fpipe.on('finish', next)
    }, (next) => {
        if (!tree.owner) return next()
        if (!+tree.owner) return next('must provide a uid, username is not supported')
        fs.chown(tree.destination, +tree.owner, 0, next)
    }], (err) => {
        if (err) return cb(err, { status: 'ERROR', exception: err })
        cb(null, { status: 'template written to file' })
    })
}
<commit_msg>lol....<commit_after>/*
 * Copyright (c) 2016 prussian <genunrest@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var fs = require('fs'),
    path = require('path'),
    mkdirp = require('mkdirp'),
    waterfall = require('async.waterfall')

module.exports = (tree, cb) => {
    var template
    try {
        template = require(
            path.join(__dirname, 'templates', tree.source)
        )(tree.variables)
    }
    catch (err) {
        return cb(err, {
            status: 'failed to template, may be a syntax error',
            exception: err
        })
    }

    waterfall([(next) => {
        if (!tree.mkdir) return next()
        mkdirp(path.dirname(tree.destination), next)
    }, (next) => {
        var fpipe
        fpipe = fs.createWriteStream(
            tree.destination,
            { mode: parseInt(tree.mode, 8) }
        ).write(template)
        fpipe.on('error', next)
        fpipe.on('finish', next)
    }, (next) => {
        if (!tree.owner) return next()
        if (!+tree.owner) return next('must provide a uid, username is not supported')
        fs.chown(tree.destination, +tree.owner, 0, next)
    }], (err) => {
        if (err) return cb(err, { status: 'ERROR', exception: err })
        cb(null, { status: 'template written to file' })
    })
}
<|endoftext|>