module.exports = function(grunt) {
  grunt.initConfig({
    jshint: {
      all: ['**/*.js', '!**/node_modules/**'],
      options: {
        newcap: false
      }
    },

    generation: {
      all: {
        src: ['lib/components/*.js'],
        docs: {
          markdown: {
            byName: {dest: 'docs/markdown/byName.md', pre: 'docs/templates/markdownNamePre.md' },
            byCategory: { dest: 'docs/markdown/byCategory.md', pre: 'docs/templates/markdownCategoryPre.md' }
          },

          html: {
            byName: {
              dest: 'docs/html/index.html',
              pre: 'docs/templates/HTMLNamePre.html',
              post: 'docs/templates/HTMLNamePost.html'
            },

            byCategory: {
              dest: 'docs/html/byCategory.html',
              pre: 'docs/templates/HTMLCategoryPre.html',
              post: 'docs/templates/HTMLCategoryPost.html'
            }
          }
        }
      }
    },

    watch: {
      files: ['lib/**/*.js', 'test/**/*.js', 'docgen/**/*.js', 'Gruntfile.js'],
      tasks: ['jshint', 'generation']
    }
  });

  var tasks = ['jshint', 'watch'];
  tasks.map(function(task) {
    grunt.loadNpmTasks('grunt-contrib-' + task);
  });

  grunt.loadTasks('customGruntTasks');
  grunt.registerTask('default', ['watch']);
};

module.exports = function(grunt) {
  grunt.initConfig({
    jshint: {
      all: ['**/*.js', '!**/node_modules/**'],
      options: {
        newcap: false
      }
    },

    generation: {
      docs: {
        src: ['lib/components/*.js'],
        docs: {
          markdown: {
            byName: {dest: 'docs/markdown/byName.md', pre: 'docs/templates/markdownNamePre.md' },
            byCategory: { dest: 'docs/markdown/byCategory.md', pre: 'docs/templates/markdownCategoryPre.md' }
          },

          html: {
            byName: {
              dest: 'docs/html/index.html',
              pre: 'docs/templates/HTMLNamePre.html',
              post: 'docs/templates/HTMLNamePost.html'
            },

            byCategory: {
              dest: 'docs/html/byCategory.html',
              pre: 'docs/templates/HTMLCategoryPre.html',
              post: 'docs/templates/HTMLCategoryPost.html'
            }
          }
        }
      }
    },

    watch: {
      lint: {
        files: ['customGruntTasks/generation.js', 'docgen/**/*.js', 'Gruntfile.js', 'lib/**/*.js', 'test/**/*.js'],
        tasks: ['jshint']
      },

      helpGeneration: {
        files: ['customGruntTasks/generation.js', 'docs/templates/*', 'docgen/**/*.js', 'lib/**/*.js'],
        tasks: ['generation:docs']
      }
    }
  });

  var tasks = ['jshint', 'watch'];
  tasks.map(function(task) {
    grunt.loadNpmTasks('grunt-contrib-' + task);
  });

  grunt.loadTasks('customGruntTasks');
  grunt.registerTask('default', ['watch']);
};

Tweak watch task configs: separate linting from help generation, and add the templates to the files that trigger help generation


/* jshint node: true */

module.exports = function (grunt) {
  'use strict';

  // Force use of Unix newlines
  grunt.util.linefeed = '\n';

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    jshint: {
      src: {
        options: {
          jshintrc: true,
          ignores: 'node_modules/**'
        },
        src: ['**/*.js']
      }
    },
    jscs: {
      gruntfile: {
        src: ['Gruntfile.js']
      },
      src: {
        src: ['**/*.js']
      }
    },
    copy: {
      chrome: {
        src: 'chrome/**',
        dest: 'dist/'
      }
    },
    zip: {
      'dist/chrome.crx': 'chrome/'
    }
  });

  require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});

  grunt.registerTask('dist', ['copy', 'zip']);
  grunt.registerTask('test', ['jshint', 'jscs']);
  grunt.registerTask('default', ['dist', 'test']);
};

/* jshint node: true */

module.exports = function (grunt) {
  'use strict';

  // Force use of Unix newlines
  grunt.util.linefeed = '\n';

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    jshint: {
      src: {
        options: {
          jshintrc: true,
          ignores: 'node_modules/**'
        },
        src: ['**/*.js']
      }
    },
    jscs: {
      gruntfile: {
        src: ['Gruntfile.js']
      },
      src: {
        src: ['**/*.js']
      }
    },
    copy: {
      chrome: {
        src: 'chrome/**',
        dest: 'dist/'
      }
    },
    zip: {
      chrome: {
        src: 'chrome/',
        dest: 'dist/chrome.crx'
      }
    }
  });

  require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});

  grunt.registerTask('dist', ['copy', 'zip']);
  grunt.registerTask('test', ['jshint', 'jscs']);
  grunt.registerTask('default', ['dist', 'test']);
};

Use File Array Format for zip task


'use strict';

module.exports = function(grunt) {
  grunt.initConfig({
    jshint: {
      all: [
        'src/*.js'
      ],
      options: {
        jshintrc: '.jshintrc'
      }
    },
    watch: {
      all: {
        files: [
          'src.*.js'
        ],
        tasks: ['default']
      }
    },
    simplemocha: {
      options: {
        globals: ['should'],
        ignoreLeaks: false,
        ui: 'bdd',
        reporter: 'spec'
      },
      all: {
        src: ['test/*.js']
      }
    },
  });
  grunt.loadNpmTasks('grunt-simple-mocha');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('dev', ['jshint','simplemocha','watch']);
  grunt.registerTask('default', ['jshint','simplemocha']);
};

'use strict';

module.exports = function(grunt) {
  grunt.initConfig({
    jshint: {
      all: [
        'src/*.js'
      ],
      options: {
        jshintrc: '.jshintrc'
      }
    },
    watch: {
      all: {
        files: [
          'src/*.js',
          'test/*.js'
        ],
        tasks: ['default']
      }
    },
    simplemocha: {
      options: {
        globals: ['should'],
        ignoreLeaks: false,
        ui: 'bdd',
        reporter: 'spec'
      },
      all: {
        src: ['test/*.js']
      }
    },
  });
  grunt.loadNpmTasks('grunt-simple-mocha');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('dev', ['jshint','simplemocha','watch']);
  grunt.registerTask('default', ['jshint','simplemocha']);
};

Add all src and test files to watch


const TwitterPostBase = require('./TwitterPostBase');
const { captureGearScreenshot } = require('@/app/screenshots');
const { readData, getTopOfCurrentHour } = require('@/common/utilities');

class GearTweet extends TwitterPostBase {
    getKey() { return 'gear'; }
    getName() { return 'Gear'; }

    getMerchandises() {
        return readData('merchandises.json').merchandises;
    }

    getDataTime() {
        // We only have end_times for merchandise items, so we need to track the latest end_time
        let endTimes = this.getMerchandises().map(m => m.end_time);
        let lastEndTime = Math.max(...endTimes);
        return lastEndTime;
    }

    getData() {
        return this.getMerchandises().find(m => m.end_time == this.getDataTime());
    }

    getTestData() {
        let merchandises = this.getMerchandises();
        return merchandises[merchandises.length - 1];
    }

    getImage() {
        return captureGearScreenshot(this.getDataTime());
    }

    getText(data) {
        return `Up now on SplatNet: ${data.gear.name} with ${data.skill.name} #splatnet2`;
    }
}

module.exports = GearTweet;

const TwitterPostBase = require('./TwitterPostBase');
const { captureGearScreenshot } = require('@/app/screenshots');
const { readData, getTopOfCurrentHour } = require('@/common/utilities');

class GearTweet extends TwitterPostBase {
    getKey() { return 'gear'; }
    getName() { return 'Gear'; }

    getMerchandises() {
        return readData('merchandises.json').merchandises;
    }

    getDataTime() {
        // We only have end_times for merchandise items, so we need to track the latest end_time
        let endTimes = this.getMerchandises().map(m => m.end_time);
        let lastEndTime = Math.max(...endTimes);
        return lastEndTime;
    }

    getData() {
        return this.getMerchandises().find(m => m.end_time == this.getDataTime());
    }

    getTestData() {
        let merchandises = this.getMerchandises();
        return merchandises[merchandises.length - 1];
    }

    getImage(data) {
        let now = getTopOfCurrentHour();
        return captureGearScreenshot(now);
    }

    getText(data) {
        return `Up now on SplatNet: ${data.gear.name} with ${data.skill.name} #splatnet2`;
    }
}

module.exports = GearTweet;

Revert "Fix a mistake, this should use the specified tweet time"


'use strict';
var moment = require('moment');

module.exports = function(app) {

    app.get('/:query', function(req, res) {
        var date = req.params.query;
        var unix = null;
        var natural = null;

        // Check for initial unix time
        if (+date >= 0) {
            unix = +date;
            natural = unixToNat(unix);
        }

        // Check for initial natural time
        if (isNaN(+date) && moment(date, "MMMM D, YYYY").isValid()) {
            unix = natToUnix(date);
            natural = unixToNat(unix);
        }

        var dateObj = { "unix": unix, "natural": natural };
        res.send(JSON.stringify(dateObj));

    });

    function natToUnix(date) {
        // Conver from natural date to unix timestamp
        return moment(date, "MMMM D, YYYY").format("X");
    }

    function unixToNat(unix) {
        // Convert unix timestamp to natural date
        return moment.unix(unix).format("MMMM D, YYYY");
    }

};

'use strict';
var moment = require('moment');

module.exports = function(app) {

    app.get('/:query', function(req, res) {
        var date = req.params.query;
        var unix = null;
        var natural = null;

        // Check for initial unix time
        if (+date >= 0) {
            unix = +date;
            natural = unixToNat(unix);
        }

        // Check for initial natural time
        if (isNaN(+date) && moment(date, "MMMM D, YYYY").isValid()) {
            unix = natToUnix(date);
            natural = unixToNat(unix);
        }

        var dateObj = { "unix": unix, "natural": natural };
        res.send(dateObj);

    });

    function natToUnix(date) {
        // Conver from natural date to unix timestamp
        return moment(date, "MMMM D, YYYY").format("X");
    }

    function unixToNat(unix) {
        // Convert unix timestamp to natural date
        return moment.unix(unix).format("MMMM D, YYYY");
    }

};

Use json instead of string


class TimeSync {
  constructor() {
    this.ts = undefined;
  }

  init() {
    if (!this.ts) {
      this.ts = timesync.create({
        server: '/timesync',
        interval: 60000
      });
    }
  }

  now() {
    this.init();
    return parseInt(this.ts.now().toFixed());
  }

  timestamp() {
    this.init();
    return (new Date(this.ts.now())).toLocaleTimeString();
  }

  humanTime(millisec) {
    var seconds = (millisec / 1000).toFixed(0);
    var minutes = Math.floor(seconds / 60);
    var hours = "";
    if (minutes > 59) {
        hours = Math.floor(minutes / 60);
        hours = (hours >= 10) ? hours : "0" + hours;
        minutes = minutes - (hours * 60);
        minutes = (minutes >= 10) ? minutes : "0" + minutes;
    }

    seconds = Math.floor(seconds % 60);
    seconds = (seconds >= 10) ? seconds : "0" + seconds;
    if (hours != "") {
        return hours + ":" + minutes + ":" + seconds;
    }
    return minutes + ":" + seconds;
  }
}

timeSync = new TimeSync();

class TimeSync {
  constructor() {
    this.ts = undefined;
  }

  init() {
    if (!this.ts) {
      this.ts = timesync.create({
        server: '/timesync',
        interval: 60000,
        repeat: 1
      });
    }
  }

  now() {
    this.init();
    return parseInt(this.ts.now().toFixed());
  }

  timestamp() {
    this.init();
    return (new Date(this.ts.now())).toLocaleTimeString();
  }

  humanTime(millisec) {
    var seconds = (millisec / 1000).toFixed(0);
    var minutes = Math.floor(seconds / 60);
    var hours = "";
    if (minutes > 59) {
        hours = Math.floor(minutes / 60);
        hours = (hours >= 10) ? hours : "0" + hours;
        minutes = minutes - (hours * 60);
        minutes = (minutes >= 10) ? minutes : "0" + minutes;
    }

    seconds = Math.floor(seconds % 60);
    seconds = (seconds >= 10) ? seconds : "0" + seconds;
    if (hours != "") {
        return hours + ":" + minutes + ":" + seconds;
    }
    return minutes + ":" + seconds;
  }
}

timeSync = new TimeSync();

Set timesync repeat to 1


'use strict';

// DEV TIME CODE
if (FAKE_SERVER) {
    require('fake');
}
// DEV TIME CODE

require('./index.scss');

var $ = require('$jquery');
var util = require('lib/util');
var state = require('./state');
var repository = require('./repository');
var sections = require('./sections/section');

//var details = args.newData.hud;
var setup = state.current();

// get into dom asap to trigger asset loading
$(function() {
	var html = '

Glimpse

'
	$(html).appendTo('body');
});

// only load things when we have the data ready to go
repository.getData(function(details) {
	$(function() { setTimeout(function() {
		// TODO: need to find a better place for this
		$('.glimpse-icon').attr('href', util.resolveClientUrl(util.currentRequestId(), true))

		// generate the html needed for the sections
		var html = sections.render(details, setup);

		// insert the html into the dom
		var holder = $(html).appendTo('.glimpse-hud');

		// force the correct state from previous load
		state.setup(holder);

		// setup events that we need to listen to
		sections.postRender(holder);
	}, 0); });
});

'use strict';

// DEV TIME CODE
if (FAKE_SERVER) {
    require('fake');
}
// DEV TIME CODE

require('./index.scss');

var $ = require('$jquery');
var util = require('lib/util');
var state = require('./state');
var repository = require('./repository');
var sections = require('./sections/section');

//var details = args.newData.hud;
var setup = state.current();

// get into dom asap to trigger asset loading
$(function() {
	var url = util.resolveClientUrl(util.currentRequestId(), true);
	var html = '

Glimpse

'
	$(html).appendTo('body');
});

// only load things when we have the data ready to go
repository.getData(function(details) {
	$(function() { setTimeout(function() {
		// generate the html needed for the sections
		var html = sections.render(details, setup);

		// insert the html into the dom
		var holder = $(html).appendTo('.glimpse-hud');

		// force the correct state from previous load
		state.setup(holder);

		// setup events that we need to listen to
		sections.postRender(holder);
	}, 0); });
});

Change logic of where href is set for the root anchor


import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return this.get('store').findAll('podcast');
  }
});

import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return this.store.findAll('podcast');
  }
});

Remove get from store instantiation


'use strict';

import cross from './cross';
import baryCenter from './bary-center';

const crossAll = (g, layers) => {
  let count = 0;
  for (let i = 1; i < layers.length; ++i) {
    count += cross(g, layers[i - 1], layers[i]);
  }
  return count;
};

const crossingReduction = (g, layers) => {
  const n = layers.length,
        repeat = 8;
  let c0 = Infinity,
      c1 = crossAll(g, layers);
  for (let loop = 0; loop < repeat && c0 !== c1; ++loop) {
    for (let i = 1; i < n; ++i) {
      baryCenter(g, layers[i - 1], layers[i]);
    }
    for (let i = n - 1; i > 0; --i) {
      baryCenter(g, layers[i - 1], layers[i], true);
    }
    c0 = c1;
    c1 = crossAll(g, layers);
  }
};

export default crossingReduction;

'use strict';

import baryCenter from './bary-center';

const crossingReduction = (g, layers) => {
  const n = layers.length,
        repeat = 8;
  for (let loop = 0; loop < repeat; ++loop) {
    for (let i = 1; i < n; ++i) {
      baryCenter(g, layers[i - 1], layers[i]);
    }
    for (let i = n - 1; i > 0; --i) {
      baryCenter(g, layers[i - 1], layers[i], true);
    }
  }
};

export default crossingReduction;

Disable crossing count in crossing reduction


/**
 * Create a snippet from selected text, add a name and automatically open
 * properties to add keybinding.
 *
 * A popup UI allows creation of the snippet name
 *
 * Type:  keybound
 * Usage: Add a keybinding of your liking in it's properties
 *
 * @source        https://github.com/Komodo/macros
 * @author        Carey Hoffman
 * @version       0.1
 */

// Create a base snippet with the selected text
scimoz = ko.views.manager.currentView.scimoz;
var snip =
   ko.projects.addSnippetFromText(scimoz.selText);
//create a date to be used as a unique name on the snippet
var d = new  Date();
// Create a unique default name string
var defaultName = "New Snippet - " + d.toLocaleTimeString().substr(0,8).trim()
// Ask for a name or provide the unique default
var name = ko.interpolate.interpolateStrings("%(ask:Snippet Name: " +
                                             defaultName + ")")
// Assign the name to the snippet name attribute
snip.name = name;
// Open the snippet options to set a keybinding
ko.projects.snippetProperties(snip);

Add comment header for style points.


import React from 'react';
import { Link } from 'react-router-dom';

const BorrowedBooks = (props) => {
  const { books } = props;
  if (!books.length) {
    return (

You have no borrowed books

    );
  }

  return (

                        Book
                        Date Borrowed
                        Status
                        Date Returned

                    { books.map((book, index) =>

                            <Link to= {`/books/${book.bookId}`}> { book.borrowedBooks.title } </Link>
                             { book.createdAt.split('T')[0] }
                             { book.status }
                             { book.status === 'Returned' ? book.updatedAt.split('T')[0] : '' }
                            { book.status !== 'Returned' &&
                            <button>Return</button>
                            }

)}

  );
};

export default BorrowedBooks;

import React from 'react';
import { Link } from 'react-router-dom';

const BorrowedBooks = (props) => {
  const {
    books, returnBook, user, isSendingRequest, returnRequests,
  } = props;
  console.log(props);

  if (!books.length) {
    return (

You have no borrowed books

    );
  }

  return (

                        Book
                        Date Borrowed
                        Status
                        Date Returned

                    { books.map((book, index) =>

                            <Link to= {`/books/${book.bookId}`}> { book.borrowedBooks.title } </Link>
                             { book.createdAt.split('T')[0] }
                             { book.status }
                             { book.status === 'Returned' ? book.updatedAt.split('T')[0] : '' }
                            { book.status !== 'Returned' &&
                            !returnRequests.find(request =>
                                request.bookId === book.bookId) &&
                            <button onClick = { returnBook.bind(null, user.id, book.bookId) }
                            className = "btn btn-small btn-wave waves-effect red"
                            disabled = { isSendingRequest } >Return</button>
                            }

)}

  );
};

export default BorrowedBooks;

Add method to return book in component


import React from 'react-native'
import { Fonts, Metrics, Colors } from '../Themes/'

const NavigationStyle = React.StyleSheet.create({
  titleWrapper: {
    flex: 1,
    padding: Metrics.baseMargin,
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center'
  },
  navTitle: {
    color: Colors.black,
    fontSize: Metrics.fonts.regular,
    fontFamily: Fonts.bold,
    justifyContent: 'center',
    alignSelf: 'center'
  },
  navSubtitle: {
    flex: 1,
    color: Colors.black,
    fontSize: Metrics.fonts.medium,
    fontFamily: Fonts.base,
    alignSelf: 'center'
  },
  backButtonText: {
    color: Colors.white,
    marginTop: 8,
    marginLeft: 8,
    fontFamily: Fonts.bold,
    padding: Metrics.baseMargin
  },
  navigationBar: {
    backgroundColor: Colors.steel
  },
  settingsButton: {
    paddingRight: Metrics.baseMargin,
    paddingTop: Metrics.baseMargin + 3
  }
})

export default NavigationStyle

import React from 'react-native'
import { Fonts, Metrics, Colors } from '../Themes/'

const NavigationStyle = React.StyleSheet.create({
  titleWrapper: {
    flex: 1,
    padding: Metrics.baseMargin,
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center'
  },
  navTitle: {
    color: Colors.black,
    fontSize: Metrics.fonts.regular,
    fontFamily: Fonts.bold,
    justifyContent: 'center',
    alignSelf: 'center'
  },
  navSubtitle: {
    flex: 1,
    color: Colors.black,
    fontSize: Metrics.fonts.medium,
    fontFamily: Fonts.base,
    alignSelf: 'center'
  },
  backButton: {
    color: Colors.black,
    padding: Metrics.baseMargin
  },
  navigationBar: {
    backgroundColor: Colors.steel
  },
  settingsButton: {
    paddingRight: Metrics.baseMargin,
    paddingTop: Metrics.baseMargin + 3
  }
})

export default NavigationStyle

Fix nav bar back style


/*jshint esnext: true */
var mongodb = require('mongodb');

/**
 * Health check a mongodb resource.
 *
 * @param {Object} setup: http check setup with fields:
 * - uri: a resource URI
 * - connectTimeout: MongoDB connect timeout in milliseconds
 * - TODO databases: an array of database names that should exist, OK when all databases exist
 * @param {Function} cb: standard cb(err, result) callback
 */
function check(setup, cb) {
  const CONNECT_TIMEOUT = 2000;
  var result = { uri: setup.uri },
    opts = {
      server: {
        socketOptions: {
          connectTimeoutMS: setup.connectTimeout || CONNECT_TIMEOUT
        }
      }
    };
  mongodb.MongoClient.connect(setup.uri , opts, function(err, conn) {
    if (err) {
      result.status = 'FAIL';
      result.desc = err.message;
    } else {
      conn.close();
      result.status = 'OK';
    }
    cb(null, result);
  });
}

exports.check = check;

/*jshint esnext: true */
var mongodb = require('mongodb');

/**
 * Health check a mongodb resource.
 *
 * @param {Object} setup: http check setup with fields:
 * - uri: a resource URI
 * - connectTimeout: MongoDB connect timeout in milliseconds
 * @param {Function} cb: standard cb(err, result) callback
 */
function check(setup, cb) {
  const CONNECT_TIMEOUT = 2000;
  var result = { uri: setup.uri },
    opts = {
      server: {
        socketOptions: {
          connectTimeoutMS: setup.connectTimeout || CONNECT_TIMEOUT
        }
      }
    };
  mongodb.MongoClient.connect(setup.uri , opts, function(err, conn) {
    if (err) {
      result.status = 'FAIL';
      result.desc = err.message;
    } else {
      conn.close();
      result.status = 'OK';
    }
    cb(null, result);
  });
}

exports.check = check;

Drop databases setup field, not needed since database name can be added to connection string.


angular
	.module('ngSharepoint')
	.provider('$sp', function() {
		var siteUrl = '';
		var connMode = 'JSOM'; //possible values: JSOM, REST
		var token = false;
		var autoload = true;

		return {
			setSiteUrl: function (newUrl) {
				siteUrl = newUrl;
			},
			setConnectionMode: function(newConnMode) { //Only JSOM Supported for now
				if (newConnMode === 'JSOM' || newConnMode === 'REST') {
					connMode = newConnMode;
				}
			},
			setAccessToken: function(newToken) {
				token = newToken;
			},
			setAutoload: function(newAutoload) {
				autoload = newAutoload;
			},
			$get: function() {
				return ({
					getSiteUrl: function() {
						return siteUrl;
					},
					getConnectionMode: function() {
						return connMode;
					},
					getAccessToken: function(token) {
						return token;
					},
					getContext: function() {
						return new SP.ClientContext(siteUrl);
					},
					getAutoload: function() {
						return autoload;
					}
				});
			}
		};
	});

angular
	.module('ngSharepoint')
	.provider('$sp', $spProvider);

function $spProvider() {
	var siteUrl = '';
	var connMode = 'JSOM';
	var token = false;
	var autoload = true;

	var provider = {
		setSiteUrl: setSiteUrl,
		setConnectionMode: setConnectionMode,
		setAccessToken: setAccessToken,
		setAutoload: setAutoload,
		$get: $sp
	};
	return provider;

	function setSiteUrl(newUrl) {
		siteUrl = newUrl;
	}
	function setConnectionMode(newConnMode) { //Only JSOM Supported for now
		if (newConnMode === 'JSOM' || newConnMode === 'REST') {
			connMode = newConnMode;
		}
	}
	function setAccessToken(newToken) {
		token = newToken;
	}
	function setAutoload(newAutoload) {
		autoload = newAutoload;
	}

	function $sp() {
		var service = {
			getSiteUrl: getSiteUrl,
			getConnectionMode: getConnectionMode,
			getAccessToken: getAccessToken,
			getContext: getContext,
			getAutoload: getAutoload
		};
		return service;

		function getContext() {
			return new SP.ClientContext();
		}
		function getSiteUrl() {
			return siteUrl;
		}
		function getConnectionMode() {
			return connMode;
		}
		function getAccessToken() {
			return token;
		}
		function getAutoload() {
			return autoload;
		}
	}
}

Use named functions for better readability


var RTCIceCandidate       = mozRTCIceCandidate       || webkitRTCIceCandidate       || RTCIceCandidate;
var RTCPeerConnection     = mozRTCPeerConnection     || webkitRTCPeerConnection     || RTCPeerConnection;
var RTCSessionDescription = mozRTCSessionDescription || webkitRTCSessionDescription || RTCSessionDescription;

exports.RTCIceCandidate       = RTCIceCandidate;
exports.RTCPeerConnection     = RTCPeerConnection;
exports.RTCSessionDescription = RTCSessionDescription;

var RTCIceCandidate       = window.mozRTCIceCandidate       || window.webkitRTCIceCandidate       || window.RTCIceCandidate;
var RTCPeerConnection     = window.mozRTCPeerConnection     || window.webkitRTCPeerConnection     || window.RTCPeerConnection;
var RTCSessionDescription = window.mozRTCSessionDescription || window.webkitRTCSessionDescription || window.RTCSessionDescription;

exports.RTCIceCandidate       = RTCIceCandidate;
exports.RTCPeerConnection     = RTCPeerConnection;
exports.RTCSessionDescription = RTCSessionDescription;

Fix bug to allow to detect correctly native implementations


import axios from 'axios'
import { observable, action } from 'mobx'

import { API_URL } from '../constants'

export default class PagesStore {
  allowedPages = ['about', 'contacts', 'home', 'portfolio']
  sessionsStore;
  @observable pages = []

  constructor(sessionsStore) {
    this.sessionsStore = sessionsStore
  }

  @action fetchIndex() {
    let headers = this.sessionsStore.getAuthHeaders()
    axios({
      method: 'GET',
      url: `${API_URL}/pages`,
      data: null,
      headers: headers
    }).then((response) => {
      if (response.status == 200) {
        this.pages = response.data
      }
    })
  }

  @action fetchShow(slug) {
    let headers = this.sessionsStore.getAuthHeaders()
    let request = axios({
      method: 'GET',
      url: `${API_URL}/pages/${slug}`,
      data: null,
      headers: headers
    })
    return request
  }

  @action update(slug, params) {
    let headers = this.sessionsStore.getAuthHeaders()
    let request = axios({
      method: 'PUT',
      url: `${API_URL}/pages/${slug}`,
      data: params,
      headers: headers
    })
    return request
  }
}

import axios from 'axios'
import { observable, action } from 'mobx'

import { API_URL } from '../constants'

export default class PagesStore {
  allowedPages = ['about', 'contacts', 'guides', 'home', 'open-source', 'portfolio']
  sessionsStore;
  @observable pages = []

  constructor(sessionsStore) {
    this.sessionsStore = sessionsStore
  }

  @action fetchIndex() {
    let headers = this.sessionsStore.getAuthHeaders()
    axios({
      method: 'GET',
      url: `${API_URL}/pages`,
      data: null,
      headers: headers
    }).then((response) => {
      if (response.status == 200) {
        this.pages = response.data
      }
    })
  }

  @action fetchShow(slug) {
    let headers = this.sessionsStore.getAuthHeaders()
    let request = axios({
      method: 'GET',
      url: `${API_URL}/pages/${slug}`,
      data: null,
      headers: headers
    })
    return request
  }

  @action update(slug, params) {
    let headers = this.sessionsStore.getAuthHeaders()
    let request = axios({
      method: 'PUT',
      url: `${API_URL}/pages/${slug}`,
      data: params,
      headers: headers
    })
    return request
  }
}

Add guides and open source static pages


// To remove expired alerts from the alerta database run this script from cron like so:
// * * * * * /usr/bin/mongo --quiet monitoring /opt/alerta/sbin/removeExpiredAlerts.js
now = new Date();
db.alerts.remove({ 'status': 'CLOSED', 'expireTime': { $lt: now }});

// To remove expired alerts from the alerta database run this script from cron like so:
// * * * * * /usr/bin/mongo --quiet monitoring /opt/alerta/sbin/removeExpiredAlerts.js
now = new Date();
db.alerts.remove({'status': 'CLOSED'});
db.alerts.remove({'expireTime': { $lt: now }});

Remove expired OR closed alerts


// To mark expired and old alerts in the alerta database run this script from cron like so:
// * * * * * /usr/bin/mongo --quiet monitoring /opt/alerta/sbin/removeExpiredAlerts.js
now = new Date();
db.alerts.update({ 'status': 'OPEN', 'expireTime': { $lt: now }}, { $set: {'status': 'EXPIRED' });

ago = new Date(new Date() - 2*60*60*1000);
db.alerts.update({ 'status': 'CLOSED', 'lastReceiveTime': { $lt: ago }}, { $set: {'status': 'DELETED' }} );

// To mark expired and old alerts in the alerta database run this script from cron like so:
// * * * * * /usr/bin/mongo --quiet monitoring /opt/alerta/sbin/removeExpiredAlerts.js
now = new Date();
db.alerts.update({ status: 'OPEN', expireTime: { $lt: now }}, { $set: { status: 'EXPIRED' }, $push: { history: {status: 'EXPIRED', updateTime: now }}});

ago = new Date(new Date() - 2*60*60*1000);
db.alerts.update({ status: 'CLOSED', lastReceiveTime: { $lt: ago }}, { $set: { status: 'DELETED' }, $push: { history: {status: 'EXPIRED', updateTime: now }}});

Fix history update to expired alerts cron


function recipeSearch(input) {
  $.ajax({
    url: "/recipes",
    data: input,
  }).done(function(recipeItemPartial) {
    $(recipeItemPartial).appendTo(".main-searchbar");
  });
}

var throttledSearch = _.throttle(recipeSearch, 300);

$(document).ready(function() {

    $(".form-control").keyup(function(event){
        $(".drop-down").remove();
        event.preventDefault();
        var input = $(this).serialize();
        if ($(this).val().length > 1) {
          throttledSearch(input);
        }
    });

    $(document).on("mouseover", "mark", function(){
      $("div").removeClass("hovered-term");
      var container = ".scrollable";
      text = $(this).text().toLowerCase();
      termCard = $(container).find("#"+text);
      $(container).prepend(termCard).scrollTop();
      $(termCard).addClass("hovered-term");
      $
    });

});

function recipeSearch(input) {
  $.ajax({
    url: "/recipes",
    data: input,
  }).done(function(recipeItemPartial) {
    $(recipeItemPartial).appendTo(".main-searchbar");
  });
}

var throttledSearch = _.throttle(recipeSearch, 300);

$(document).ready(function() {

  $('input').focus();

    $(".form-control").keyup(function(event){
        $(".drop-down").remove();
        event.preventDefault();
        var input = $(this).serialize();
        if ($(this).val().length > 1) {
          throttledSearch(input);
        }
    });

    $(document).on("mouseover", "mark", function(){
      $("div").removeClass("hovered-term");
      var container = ".scrollable";
      text = $(this).text().toLowerCase();
      termCard = $(container).find("#"+text);
      $(container).prepend(termCard).scrollTop();
      $(termCard).addClass("hovered-term");
      $
    });

});

Add blinky cursor upon page load


const express = require('express');
const router = express.Router();

const mongoose = require('mongoose');
const User = require('../models/user.js');

const jwt = require('jsonwebtoken');
const jwtConfig = require('../jwt_config');

router.post('/', (request, response) => {
  const username = request.body.username;
  User.findOne({username: username}, (err, db_response) => {
    if (err) {
      console.error(err);
      response.status(500).send();
    } else if (!db_response) {
      response.status(404).send();
    } else {
      const id = db_response._id;
      const token = jwt.sign({username: username, userId: id}, jwtConfig.key);
      response.status(200).send(token);
    }
  });
});

module.exports = router;

const express = require('express');
const router = express.Router();

const mongoose = require('mongoose');
const User = require('../models/user.js');

const jwt = require('jsonwebtoken');
const jwtConfig = require('../jwt_config');

router.post('/', (request, response) => {
  const username = request.body.username;
  User.findOne({username: username}, (err, db_response) => {
    if (err) {
      console.error(err);
      response.status(500).send();
    } else if (!db_response) {
      response.status(404).send();
    } else {
      const id = db_response._id;
      // 1 day JWT token expiration
      const token = jwt.sign(
          {username: username, userId: id}, jwtConfig.key, {expiresIn: '1day'});
      response.status(200).send(token);
    }
  });
});

module.exports = router;

Set expiration time for JWT to 1 day


import React from 'react'
import PropTypes from 'prop-types'

export const Content = ({ children, clouds }) => (
  <main>
    {children}

    <style jsx>{`
      @import 'colors';

      main {
        background-color: $white;
        padding: 2em 0 10em;
        display: flex;
        flex-direction: column;
        flex: 1;

        ${clouds && (`
          background: url('/static/images/clouds.svg') bottom / 101% no-repeat,
                      linear-gradient(to top, #41dcd7, #3083b2);
        `)}
      }
    `}</style>
  </main>
)

Content.propTypes = {
  children: PropTypes.node,
  clouds: PropTypes.bool
}

Content.defaultProps = {
  clouds: false
}

export default Content

import React from 'react'
import PropTypes from 'prop-types'

export const Content = ({ children, clouds }) => (
  <main>
    {children}

    <style jsx>{`
      @import 'colors';

      main {
        background-color: $white;
        padding: 2em 0 10em;
        display: flex;
        flex-direction: column;
        flex: 1;

        ${clouds && (`
          background: url('/static/images/clouds.svg') bottom -120px right 0, linear-gradient(to top, #41dcd7, #3083b2);
          background-repeat: no-repeat;
          background-size: 100%;
        `)}
      }
    `}</style>
  </main>
)

Content.propTypes = {
  children: PropTypes.node,
  clouds: PropTypes.bool
}

Content.defaultProps = {
  clouds: false
}

export default Content

Move clouds down a little


/* @flow */

export class Employee {
    name: string;
    balance: number;

    constructor(name: string) {
	this.name = name;
	this.balance = 0.0;
    }
};

export class Snack {
    name: string;
    price: number;

    constructor(name: string, price: number) {
	this.name = name;
	this.price = price;
    }
};

export let employees = [
    new Employee('Chris Spahr'),
    new Employee('Phil Cairns'),
    new Employee('Phil Nicolcev'),
    new Employee("Gaelan D'costa")
];

export let snacks = [
    new Snack('Perrier', 2.00),
    new Snack('Dr. Pepper', 0.50),
    new Snack('Soylent', 2.00)
];

/* @flow */

export class Employee {
    name: string;
    balance: number;

    constructor(name: string, balance: number) {
	this.name = name;
	this.balance = balance;
    }
};

export class Snack {
    name: string;
    price: number;

    constructor(name: string, price: number) {
	this.name = name;
	this.price = price;
    }
};

export let employees = [
    new Employee('Chris Spahr', 0),
    new Employee('Phil Cairns', 0),
    new Employee('Phil Nicolcev', 0),
    new Employee("Gaelan D'costa", 20)
];

export let snacks = [
    new Snack('Perrier', 2.00),
    new Snack('Dr. Pepper', 0.50),
    new Snack('Soylent', 2.00)
];

Mark one person as having money


const knex = require('../database')

module.exports.findOne = (username) => new Promise((resolve, reject) => {
  knex('users').select().where({username})

    // success
    .then(user => {
      if (user) { resolve(user[0]) }
      else { resolve(null) }
    })

    // error
    .catch(err => reject(err))
})

module.exports.comparePasswords = (dbPass, reqPass) => dbPass === reqPass

module.exports.createUser = (req) => new Promise((resolve, reject) => {
  const user = req.body
  knex('users').insert(user).returning('*')
    .then(resolve)
    .catch(reject)
})

Add a function to create a new user


/**
 * Module dependencies
 */

var path = require('path');
var Womb = require('child_process');
var CaptainsLog = require('captains-log');
var chalk = require('chalk');
var Sails = require('../lib/app');

/**
 * `sails inspect`
 *
 * Attach the Node inspector and lift a Sails app.
 * You can then use Node inspector to debug your app as it runs.
 *
 */
module.exports = function(cmd) {

  var extraArgs = cmd.parent.rawArgs.slice(3);

  var log = CaptainsLog();

  // Use the app's local Sails in `node_modules` if one exists
  // But first make sure it'll work...
  var appPath = process.cwd();
  var pathToSails = path.resolve(appPath, '/node_modules/sails');
  if (!Sails.isLocalSailsValid(pathToSails, appPath)) {
    // otherwise, use the currently-running instance of Sails
    pathToSails = path.resolve(__dirname, './sails.js');
  }

  console.log();
  log.info('Running app in inspect mode...');

  log.info(chalk.grey('( to exit, type ' + '<CTRL>+<C>' + ' )'));
  console.log();

  // Spin up child process for Sails
  Womb.spawn('node', ['--inspect', pathToSails, 'lift'].concat(extraArgs), {
    stdio: 'inherit'
  });

};

/**
 * Module dependencies
 */

var path = require('path');
var Womb = require('child_process');
var CaptainsLog = require('captains-log');
var chalk = require('chalk');
var Sails = require('../lib/app');

/**
 * `sails inspect`
 *
 * Attach the Node inspector and lift a Sails app.
 * You can then use Node inspector to debug your app as it runs.
 *
 */
module.exports = function(cmd) {

  var extraArgs = cmd.parent.rawArgs.slice(3);

  var log = CaptainsLog();

  // Use the app's local Sails in `node_modules` if one exists
  // But first make sure it'll work...
  var appPath = process.cwd();
  var pathToSails = path.resolve(appPath, '/node_modules/sails');
  if (!Sails.isLocalSailsValid(pathToSails, appPath)) {
    // otherwise, use the currently-running instance of Sails
    pathToSails = path.resolve(__dirname, './sails.js');
  }

  console.log();
  log.info('Running app in inspect mode...');
  if (process.version[1] >= 8) {
    log.info('In Google Chrome, go to chrome://inspect for interactive debugging.');
    log.info('For other options, see the link below.');
  }

  log.info(chalk.grey('( to exit, type ' + '<CTRL>+<C>' + ' )'));
  console.log();

  // Spin up child process for Sails
  Womb.spawn('node', ['--inspect', pathToSails, 'lift'].concat(extraArgs), {
    stdio: 'inherit'
  });

};

Add a bit more help text for Node v8+


const requests = {
  Produce: require('./produce'),
  Fetch: {},
  Offsets: {},
  Metadata: require('./metadata'),
  LeaderAndIsr: {},
  StopReplica: {},
  UpdateMetadata: {},
  ControlledShutdown: {},
  OffsetCommit: {},
  OffsetFetch: {},
  GroupCoordinator: {},
  JoinGroup: {},
  Heartbeat: {},
  LeaveGroup: {},
  SyncGroup: {},
  DescribeGroups: {},
  ListGroups: {},
  SaslHandshake: require('./saslhandshake'),
  ApiVersions: require('./apiVersions'),
  CreateTopics: {},
  DeleteTopics: {},
}

const lookup = versions => (apiKey, definition) => {
  const version = versions[apiKey]
  const bestImplementedVersion = Math.max.apply(this, definition.versions)
  const bestSupportedVersion = Math.min(bestImplementedVersion, version.maxVersion)
  return definition.protocol({ version: bestSupportedVersion })
}

module.exports = {
  requests,
  lookup,
}

const requests = {
  Produce: require('./produce'),
  Fetch: {},
  Offsets: {},
  Metadata: require('./metadata'),
  LeaderAndIsr: {},
  StopReplica: {},
  UpdateMetadata: {},
  ControlledShutdown: {},
  OffsetCommit: {},
  OffsetFetch: {},
  GroupCoordinator: {},
  JoinGroup: {},
  Heartbeat: {},
  LeaveGroup: {},
  SyncGroup: {},
  DescribeGroups: {},
  ListGroups: {},
  SaslHandshake: require('./saslHandshake'),
  ApiVersions: require('./apiVersions'),
  CreateTopics: {},
  DeleteTopics: {},
}

const lookup = versions => (apiKey, definition) => {
  const version = versions[apiKey]
  const bestImplementedVersion = Math.max.apply(this, definition.versions)
  const bestSupportedVersion = Math.min(bestImplementedVersion, version.maxVersion)
  return definition.protocol({ version: bestSupportedVersion })
}

module.exports = {
  requests,
  lookup,
}

Fix typo when loading the SASL Handshake protocol


export {
  event,
  selection,
  select,
  selectAll
} from "d3-selection";

import "d3-transition";

export {
  chord,
  ribbon
} from "d3-chord";

export {
  scaleOrdinal,
  schemeCategory20
} from "d3-scale";

export {
  event,
  selection,
  select,
  selectAll,
  local
} from "d3-selection";

import "d3-transition";

export {
  chord,
  ribbon
} from "d3-chord";

export {
  scaleOrdinal,
  schemeCategory20
} from "d3-scale";

Add d3.local to D3 build


// Status.js Front End
// Developed by @gaarb

var APIUrl = "https://api.garb.pw/status"; // Setting the APIUrl.

var Banner = document.getElementById('banner');
var BannerMsg = document.getElementById('banner-msg');

$(document).ready(function () {
  setInterval(function () {
    $.getJSON(APIUrl, function (data) {
      if (data['login']) {
        $('#login-color').removeClass("offline");
        $('#login-color').addClass("online");
        $('#login-text').text('ONLINE');
      }
      if (data['gameserver']) {
        $('#game-color').removeClass("offline");
        $('#game-color').addClass("online");
        $('#game-text').text('ONLINE');
      }

      // Banner
      if (data.banner) {
        Banner.classList.remove('banner-disabled');
        BannerMsg.innerHTML = data.banner;
      } else {
        Banner.classList.add('banner-disabled');
      }

    })
    .fail(function() {
      $('#login-color').addClass("offline");
      $('#login-text').text('OFFLINE');

      $('#game-color').addClass("offline");
      $('#game-text').text('OFFLINE');

      Banner.classList.add('banner-disabled');
    });
  }, 1000);
});

// Status.js Front End
// Developed by @gaarb

var APIUrl = "https://api.garb.pw/status"; // Setting the APIUrl.

var Banner = document.getElementById('banner');
var BannerMsg = document.getElementById('banner-msg');

$(document).ready(function () {
  setInterval(function () {
    $.getJSON(APIUrl, function (data) {
      if (data['login']) {
        $('#login-color').removeClass("offline");
        $('#login-color').addClass("online");
        $('#login-text').text('ONLINE');
      }
      if (data['gameserver']) {
        $('#game-color').removeClass("offline");
        $('#game-color').addClass("online");
        $('#game-text').text('ONLINE');
      }

      // Banner
      if (data.banner) {
        Banner.classList.remove('banner-disabled');
        BannerMsg.innerHTML = data.banner;
      } else {
        Banner.classList.add('banner-disabled');
      }

    })
    .fail(function() {
      $('#login-color').addClass("offline");
      $('#login-text').text('OFFLINE');

      $('#game-color').addClass("offline");
      $('#game-text').text('OFFLINE');

      Banner.classList.add('banner-disabled');
    });
  }, 10000);
});

Change rate to 10 seconds.


/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import Logger from './logger';
import ConsoleAppender from './appenders/console';
import Level from './level';

const Log4js = {
  // Current version of log4js.
  version: '0.0.1',
  // Date of logger initialized.
  applicationStartDate: new Date(),
  // Hashtable of loggers.
  loggers: {},
  // Quick access to the ConsoleAppender
  ConsoleAppender: ConsoleAppender,
  // Quick access to the log levels
  Level: Level,
  // Get a logger instance. Instance is cached on categroyName level.
  getLogger: categoryNameParam => {
    // Use default logger if categoryName is not specified or invalid
    let categoryName;
    if (typeof categoryNameParam !== 'string') {
      categoryName = '[default]';
    } else {
      categoryName = categoryNameParam;
    }

    if (!Log4js.loggers[categoryName]) {
      // Create the logger for this name if it doesn't already exist
      Log4js.loggers[categoryName] = new Logger(categoryName);
    }

    return Log4js.loggers[categoryName];
  },
};

export default Log4js;

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import Logger from './logger';
import ConsoleAppender from './appenders/console';
import Level from './level';

const Log4js = {
  // Date of logger initialized.
  applicationStartDate: new Date(),
  // Hashtable of loggers.
  loggers: {},
  // Quick access to the ConsoleAppender
  ConsoleAppender: ConsoleAppender,
  // Quick access to the log levels
  Level: Level,
  // Get a logger instance. Instance is cached on categroyName level.
  getLogger: categoryNameParam => {
    // Use default logger if categoryName is not specified or invalid
    let categoryName;
    if (typeof categoryNameParam !== 'string') {
      categoryName = '[default]';
    } else {
      categoryName = categoryNameParam;
    }

    if (!Log4js.loggers[categoryName]) {
      // Create the logger for this name if it doesn't already exist
      Log4js.loggers[categoryName] = new Logger(categoryName);
    }

    return Log4js.loggers[categoryName];
  },
};

export default Log4js;

Remove version property from Log4js


import { default as Banner } from './components/Banner'
import { default as Button } from './components/Button'
import { default as DeleteButton } from './components/DeleteButton'
import { default as DeviceStatusGauge } from './components/DeviceStatusGauge'
import { default as Divider } from './components/Divider'
import { default as Filters } from './components/Filters'
import { default as Fixed } from './components/Fixed'
import { default as Input } from './components/Input'
import { default as Modal } from './components/Modal'
import { default as PineTypes } from './components/PineTypes'
import { default as ProgressBar } from './components/ProgressBar'
import { default as Provider } from './components/Provider'
import { default as SchemaSieve } from './components/Filters/SchemaSieve'
import { default as Select } from './components/Select'
import { default as Text } from './components/Text'
import { default as Textarea } from './components/Textarea'

import { Flex, Box } from './components/Grid'

export {
  Banner,
  Box,
  Button,
  DeleteButton,
  DeviceStatusGauge,
  Divider,
  Filters,
  Fixed,
  Flex,
  Input,
  Modal,
  PineTypes,
  Provider,
  ProgressBar,
  SchemaSieve,
  Select,
  Text,
  Textarea
}

import { default as Banner } from './components/Banner'
import { default as Button } from './components/Button'
import { default as CodeWithCopy } from './components/CodeWithCopy'
import { default as DeleteButton } from './components/DeleteButton'
import { default as DeviceStatusGauge } from './components/DeviceStatusGauge'
import { default as Divider } from './components/Divider'
import { default as Filters } from './components/Filters'
import { default as Fixed } from './components/Fixed'
import { default as Input } from './components/Input'
import { default as Modal } from './components/Modal'
import { default as PineTypes } from './components/PineTypes'
import { default as ProgressBar } from './components/ProgressBar'
import { default as Provider } from './components/Provider'
import { default as SchemaSieve } from './components/Filters/SchemaSieve'
import { default as Select } from './components/Select'
import { default as Text } from './components/Text'
import { default as Textarea } from './components/Textarea'

import { Flex, Box } from './components/Grid'

export {
  Banner,
  Box,
  Button,
  CodeWithCopy,
  DeleteButton,
  DeviceStatusGauge,
  Divider,
  Filters,
  Fixed,
  Flex,
  Input,
  Modal,
  PineTypes,
  Provider,
  ProgressBar,
  SchemaSieve,
  Select,
  Text,
  Textarea
}

Add CodeWithCopy component to module exports


var args = arguments[0] || {};

// Access the existing books collection.
var myBooks = Alloy.Collections.books;

// When window opens, focus the title field.
$.addbook.addEventListener('open', function(e) {
  $.titleInput.focus();
  Ti.API.error('window got opened. focus text field');
});

function addBook(e) {
  Ti.API.error(e);
};

var args = arguments[0] || {};

// Access the existing books collection.
var myBooks = Alloy.Collections.books;

// When window opens, focus the title field.
$.addbook.addEventListener('open', function(e) {
  $.titleInput.focus();
  Ti.API.error('window got opened. focus text field');
});

// Add the book to the collection and close the window.
function addBook(e) {
  var title = $.titleInput.value || 'No Title';
  var author = $.authorInput.value || 'No Author';

  // Create a "book" model.
  var book = Alloy.createModel('books', {
    title : title,
    author: author
  });

  // Add book model to the collection.
  myBooks.add(book);

  // Persiste the book in the database.
  book.save();

  $.addbook.close();
};

Add book to table view after it gets added


/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'ember-bedspacemanagement',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

module.exports = function (environment) {
  var ENV = {
    modulePrefix: 'ember-bedspacemanagement',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;

    /**
     * Enable Ember CLI Mirage in development
     *  To share a working prototype before Sails.js server is ready
     */
    ENV['ember-cli-mirage'] = {
      enabled: true
    }
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';

    /**
     * Enable Ember CLI Mirage in testing
     */
    ENV['ember-cli-mirage'] = {
      enabled: true
    }
  }

  if (environment === 'production') {
    /**
     * Disable Ember CLI Mirage in production
     */
    ENV['ember-cli-mirage'] = {
      enabled: false
    }
  }

  return ENV;
};

Update app config to enable mocks


import sha1 from 'sha1';

export function signature(secret, url, payload) {
  payload = payload ? JSON.stringify(payload) : '';

  return sha1(secret + url + payload);
}

import sha1 from 'sha1';

export function signature(secret, url, payload) {
  payload = payload ? sha1(JSON.stringify(payload)) : '';

  return sha1(secret + url + payload);
}

Fix signature generation for requests with payload


/*jslint nomen: true*/
/*global define*/
define([
    'jquery',
    'underscore',
    'orotranslation/js/translator',
    'backbone',
    'oroui/js/messenger',
    'oroui/js/app/views/base/view'
], function ($, _, __, Backbone, messenger, BaseView) {
    'use strict';

    var EmailAttachmentLink;

    /**
     * @export oroemail/js/app/views/email-attachment-link-view
     */
    EmailAttachmentLink = BaseView.extend({
        options: {},
        events: {
            'click .icon-link': 'linkAttachment'
        },

        /**
        * Constructor
        *
        * @param options {Object}
        */
        initialize: function (options) {
            this.options = _.defaults(options || {}, this.options);
            EmailAttachmentLink.__super__.initialize.apply(this, arguments);
        },

        /**
         * onClick event listener
         */
        linkAttachment: function (e) {
            e.preventDefault();
            $.getJSON(
                this.options.url,
                {},
                function (response) {
                    if (_.isUndefined(response.error)) {
                        messenger.notificationFlashMessage('success', __('oro.email.attachment.added'));
                    } else {
                        messenger.notificationFlashMessage('error', __(response.error));
                    }
                }
            );
            return false;
        }
    });

    return EmailAttachmentLink;
});

/*jslint nomen: true*/
/*global define*/
define([
    'jquery',
    'underscore',
    'orotranslation/js/translator',
    'backbone',
    'oroui/js/messenger',
    'oroui/js/app/views/base/view',
    'oroui/js/mediator'
], function ($, _, __, Backbone, messenger, BaseView, mediator) {
    'use strict';

    var EmailAttachmentLink;

    /**
     * @export oroemail/js/app/views/email-attachment-link-view
     */
    EmailAttachmentLink = BaseView.extend({
        options: {},
        events: {
            'click .icon-link': 'linkAttachment'
        },

        /**
        * Constructor
        *
        * @param options {Object}
        */
        initialize: function (options) {
            this.options = _.defaults(options || {}, this.options);
            EmailAttachmentLink.__super__.initialize.apply(this, arguments);
        },

        /**
         * onClick event listener
         */
        linkAttachment: function (e) {
            var self = this;
            e.preventDefault();
            $.getJSON(
                this.options.url,
                {},
                function (response) {
                    if (_.isUndefined(response.error)) {
                        messenger.notificationFlashMessage('success', __('oro.email.attachment.added'));
                        self.reloadAttachmentGrid();
                    } else {
                        messenger.notificationFlashMessage('error', __(response.error));
                    }
                }
            );
            return false;
        },

        reloadAttachmentGrid: function() {
            mediator.trigger('datagrid:doRefresh:attachment-grid');
        }
    });

    return EmailAttachmentLink;
});

Refresh attachment grid after click on attachment link on email


/* eslint-disable no-console */
const writeLine = (line) => console.log(line);
/* eslint-enable no-console */

const runTask = async (task) => {
    const startTime = Date.now();

    writeLine(`Starting ${task.name}`);

    await new Promise(task)
        .catch((err) => {
            writeLine(err);
            process.exit(1);
        })
        .then(() => writeLine(`Finished ${task.name} in ${Date.now() - startTime}ms`));
};

const runJobSeries = (tasks) => {
    tasks.reduce(async (previous, next) => {
        await previous;

        return runTask(next);
    }, Promise.resolve());
};

const build = (availableJobs) => {
    const startTime = Date.now();

    const jobName = Object.keys(availableJobs).includes(process.argv[2])
        ? process.argv[2]
        : 'default';

    writeLine(`Running job ${jobName}`);

    runJobSeries(availableJobs[jobName]);

    writeLine(`Done in ${Date.now() - startTime}ms`);
};

module.exports = build;

/* eslint-disable no-console */
const writeLine = (line) => console.log(line);
/* eslint-enable no-console */

const runTask = async (task) => {
    const startTime = Date.now();

    writeLine(`Starting ${task.name}`);

    return new Promise(task)
        .catch((err) => {
            writeLine(err);
            process.exit(1);
        })
        .then(() => writeLine(`Finished ${task.name} in ${Date.now() - startTime}ms`));
};

const runJobSeries = async (tasks) => tasks.reduce(async (previous, next) => {
    await previous;

    return runTask(next);
}, Promise.resolve());

const build = (availableJobs) => {
    const startTime = Date.now();

    const jobName = Object.keys(availableJobs).includes(process.argv[2])
        ? process.argv[2]
        : 'default';

    writeLine(`Running job ${jobName}`);

    runJobSeries(availableJobs[jobName])
        .then(() => writeLine(`Done in ${Date.now() - startTime}ms`));
};

module.exports = build;

Fix job timer during build.


var jwt = require('jwt-simple');
var moment = require('moment');
var config = require('../../config/config');

var authMiddleware = {};

authMiddleware.ensureAuthenticated = function (req, res, next) {
    if (!req.headers.authorization) {
        return res.status(401).send({message: 'Please make sure your request has an Authorization header'});
    }
    var token = req.headers.authorization.split(' ')[1];
    var payload = jwt.decode(token, config.TOKEN_SECRET);
    if (payload.exp <= moment().unix()) {
        return res.status(401).send({message: 'Token has expired'});
    }
    req.user = payload.user;
    next();
};

module.exports = authMiddleware;

var jwt = require('jwt-simple');
var moment = require('moment');

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

var authMiddleware = {};

authMiddleware.ensureAuthenticated = function (req, res, next) {
    if (!req.headers.authorization) {
        return res.status(401).send({message: 'Please make sure your request has an Authorization header'});
    }
    var token = req.headers.authorization.split(' ')[1];
    try {
        var payload = jwt.decode(token, config.TOKEN_SECRET);
        if (payload.exp <= moment().unix()) {
            return res.status(401).send({message: 'Token has expired'});
        }
        req.user = payload.user;
        next();
    } catch (error) {
        return res.status(401).send({message: error.message});
    }
};

module.exports = authMiddleware;

Handle case when token is not valid


import React, { Component } from 'react';
import Registry from '../utils/Registry';
import BaseComponent from './BaseComponent';
import Card from './Card';
import { pick } from 'lodash';

/**
 * @@TODO Currently in practice this only handles regions
 * MOST OF THIS LOGIC IS REPRODUCE IN THE Region Component
 * We should refactor so this is not the case
 */
export default class Dashboard extends BaseComponent {
  render() {
    let markup;
    console.log('DASH RENDER', this);
    let routeParams = pick(this.props, ['history', 'location', 'params', 'route', 'routeParams', 'routes']);
    // We wrap the whole dashboard in the route so we that we get paramater info in the els
    // @@TODO this needs to be repeated in Region because of our dumb scheme
    return (

{this.props.title}

          {this.props.components.map((element, key) => {
            let props = Object.assign(this.props.components[key], {globalData: this.state.data}, routeParams);
            let output;

            if (props.cardType !== 'undefined') {
              output =
                <Card key={key} {...element}>
                  {React.createElement(Registry.get(element.type), Object.assign(this.props.components[key], props))}
                </Card>
            } else {
              output =
                React.createElement(Registry.get(element.type), Object.assign(this.props.components[key], props))
            }
            return output;
          })}

    );
  }
}

import React, { Component } from 'react';
import Registry from '../utils/Registry';
import BaseComponent from './BaseComponent';
import Card from './Card';
import { pick } from 'lodash';

/**
 * @@TODO Currently in practice this only handles regions
 * MOST OF THIS LOGIC IS REPRODUCE IN THE Region Component
 * We should refactor so this is not the case
 */
export default class Dashboard extends BaseComponent {
  render() {
    let markup;
    console.log('DASH RENDER', this);
    let routeParams = pick(this.props, ['history', 'location', 'params', 'route', 'routeParams', 'routes']);
    // We wrap the whole dashboard in the route so we that we get paramater info in the els
    // @@TODO this needs to be repeated in Region because of our dumb scheme
    return (

{this.props.title}

          {this.props.components.map((element, key) => {
            let props = Object.assign(this.props.components[key], {globalData: this.state.data}, routeParams);
            let output;

            if (props.cardStyle) {
              output =
                <Card key={key} {...element}>
                  {React.createElement(Registry.get(element.type), Object.assign(this.props.components[key], props))}
                </Card>
            } else {
              output =
                React.createElement(Registry.get(element.type), Object.assign(this.props.components[key], props))
            }
            return output;
          })}

    );
  }
}

Fix card rendering in dash


var path = require('path');
const webpack = require('webpack')

const baseConfig = module.exports = {
    context: path.resolve(__dirname, '../'),
    entry: {
        app: './src/main.js'
    },
    output: {
        path: path.resolve(__dirname, '../dist'),
        publicPath: '/'
    },
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js',
            '@': path.resolve(__dirname, '../src'),
        },
        modules: [path.resolve(__dirname, "../../node_modules")]
    },
    module: {
        rules: [{
            test: /\.js$/,
            loader: 'babel-loader',
            include: path.resolve('src')
        }, {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader',
            options: {
                limit: 10000,
                name: 'static/img/[name].[hash:7].[ext]'
            }
        }, {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: 'url-loader',
            options: {
                limit: 10000,
                name: 'static/fonts/[name].[hash:7].[ext]'
            }
        }]
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            Tether: 'tether'
        }),
    ]
};

var path = require('path');
const webpack = require('webpack')

const baseConfig = module.exports = {
    context: path.resolve(__dirname, '../'),
    entry: {
        app: './src/main.js'
    },
    output: {
        path: path.resolve(__dirname, '../dist'),
        publicPath: '/'
    },
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js',
            '@': path.resolve(__dirname, '../src'),
        }
    },
    module: {
        rules: [{
            test: /\.js$/,
            loader: 'babel-loader',
            include: path.resolve('src')
        }, {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader',
            options: {
                limit: 10000,
                name: 'static/img/[name].[hash:7].[ext]'
            }
        }, {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: 'url-loader',
            options: {
                limit: 10000,
                name: 'static/fonts/[name].[hash:7].[ext]'
            }
        }]
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            Tether: 'tether'
        }),
    ]
};

Remove unneccesary webpack node_modules path adjustment


const path = require('path');

const projectRoot = path.resolve(__dirname, '../../../');

module.exports = {
  // use inline sourcemap for karma-sourcemap-loader
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue',
      },
      {
        test: /\.js$/,
        loader: 'babel',
        include: [
          projectRoot,
        ],
        exclude: /node_modules/,
      },
    ],
  },
  vue: {
    loaders: {
      js: 'babel'
    }
  },
  devtool: '#inline-source-map',
};

const path = require('path');

const projectRoot = path.resolve(__dirname, '../../../');

module.exports = {
  // use inline sourcemap for karma-sourcemap-loader
  module: {
    resolve: {
      extensions: ['.js', '.vue']
    },
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue',
      },
      {
        test: /\.js$/,
        loader: 'babel',
        include: [
          projectRoot,
        ],
        exclude: /node_modules/,
      }
    ],
  },
  vue: {
    loaders: {
      js: 'babel'
    }
  },
  devtool: '#inline-source-map',
};

Add resolve property to webpack config


var assert = require('assert')
var charStream = require('../app.js')

describe('random-character-stream', function() {

    function getBuffer(charGen, size) {
        var buffer = ''
        var i = 0
        while (i++ < size) {
            buffer += charGen.next().value
        }
        return buffer
    }

    context('when instantiated with a seed', function() {
        var stream_1, stream_2

        beforeEach(function() {
            var charGen_1 = charStream(123)
            var charGen_2 = charStream(123)

            stream_1 = getBuffer(charGen_1, 10)
            stream_2 = getBuffer(charGen_2, 10)
        })

        it('always returns the same characters', function() {
            assert.equal(stream_1, stream_2)
        })

    })

    context('when instantiated with an allowed character set', function() {
        var stream

        beforeEach(function() {
            var charGen = charStream(123, [97, 98, 99])
            stream = getBuffer(charGen, 100)
        })

        it('only returns characters from that set', function() {
            for (i in stream) {
                var character = stream[i]
                assert.ok(['a', 'b', 'c'].indexOf(character) !== -1)
            }
        })

    })
})

var assert = require('assert')
var charStream = require('../app.js')

describe('random-character-stream', function() {

    function getBuffer(charGen, size) {
        var buffer = ''
        var i = 0
        while (i++ < size) {
            buffer += charGen.next().value
        }
        return buffer
    }

    context('when instantiated with a seed', function() {
        var stream_1, stream_2

        beforeEach(function() {
            var charGen_1 = charStream(123)
            var charGen_2 = charStream(123)

            stream_1 = getBuffer(charGen_1, 1000)
            stream_2 = getBuffer(charGen_2, 1000)
        })

        it('always returns the same characters', function() {
            assert.equal(stream_1, stream_2)
        })

    })

    context('when instantiated with an allowed character set', function() {
        var stream

        beforeEach(function() {
            var charGen = charStream(123, [97, 98, 99])
            stream = getBuffer(charGen, 1000)
        })

        it('only returns characters from that set', function() {
            for (i in stream) {
                var character = stream[i]
                assert.ok(['a', 'b', 'c'].indexOf(character) !== -1)
            }
        })

    })
})

Set larger test stream length


'use strict';

var dependencies = require('../../package.json').dependencies;
var dependencyNames = Object.keys(dependencies);
var packages = dependencyNames.filter(function (d) {
  // Remove scoped packages
  return d[0] !== '@';
});

describe('Shared dependency', function () {
  packages.forEach(function (pkgName) {
    describe(pkgName, function () {
      var pkgDependencies = require('../../node_modules/' + pkgName + '/package.json').dependencies;
      var sharedDependencyNames = Object.keys(pkgDependencies).filter(function (d) {
        return dependencyNames.indexOf(d) !== -1;
      });

      sharedDependencyNames.forEach(function (sharedDepName) {
        var sharedDepVersion = pkgDependencies[sharedDepName];

        it('uses ' + sharedDepName + '@' + sharedDepVersion, function () {
          var dependencyVersion = dependencies[sharedDepName];

          if (sharedDepVersion !== dependencyVersion) {
            throw new Error(pkgName + ' should be using ' + sharedDepName + '@' + dependencyVersion + ' but was ' + sharedDepVersion);
          }
        });
      });
    });
  });
});

'use strict';
var execSync = require('child_process').execSync;

var dependencies = require('../../package.json').dependencies;
var dependencyNames = Object.keys(dependencies);
var dependencyPackages = dependencyNames.map(function (depName) {
  var depPackages = {};
  var depVersion = dependencies[depName];
  var cmd = 'npm view --json ' + depName + '@' + depVersion + ' dependencies';
  var result = execSync(cmd).toString();

  if (result) {
    depPackages = JSON.parse(result);
  }

  return {
    name: depName,
    dependencies: depPackages
  };
});

describe('Shared dependency', function () {
  dependencyPackages.forEach(function (depPkg) {
    describe(depPkg.name, function () {
      var sharedDependencyNames = Object.keys(depPkg.dependencies).filter(function (d) {
        return dependencyNames.indexOf(d) !== -1;
      });

      sharedDependencyNames.forEach(function (sharedDepName) {
        var sharedDepVersion = depPkg.dependencies[sharedDepName];

        it('uses ' + sharedDepName + '@' + sharedDepVersion, function () {
          var dependencyVersion = dependencies[sharedDepName];

          if (sharedDepVersion !== dependencyVersion) {
            throw new Error(depPkgName + ' should be using ' + sharedDepName + '@' + dependencyVersion + ' but was ' + sharedDepVersion);
          }
        });
      });
    });
  });
});

Use npm view to get all nested dependencies


/*

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      This file is part of the Smart Developer Hub Project:
        http://www.smartdeveloperhub.org/
      Center for Open Middleware
            http://www.centeropenmiddleware.com/
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Copyright (C) 2015 Center for Open Middleware.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
                http://www.apache.org/licenses/LICENSE-2.0
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
     limitations under the License.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
*/

'use strict';

/**
 * Get Information about the organization
 * @param callback the callback to respond with the organization info
 * @returns {Object}
 */
exports.orgInfo = function(callback) {

    //TODO By the moment we are using Dummy organization for the demo
    callback({
        "organizationid" : "Organization DePalo 1",
        "shortdesc" : "Center Open Middleware Researches ",
        "longdesc" : "Esta es la descripción larga de la organizacion y es muy útil para describirla"
    });
};

/*

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      This file is part of the Smart Developer Hub Project:
        http://www.smartdeveloperhub.org/
      Center for Open Middleware
            http://www.centeropenmiddleware.com/
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Copyright (C) 2015 Center for Open Middleware.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
                http://www.apache.org/licenses/LICENSE-2.0
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
     limitations under the License.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
*/

'use strict';

/**
 * Get Information about the organization
 * @param callback the callback to respond with the organization info
 * @returns {Object}
 */
exports.orgInfo = function(callback) {

    //TODO By the moment we are using Dummy organization for the demo
    callback({
        "organizationid" : "Organization DePalo 1",
        "description" : "Center Open Middleware Researches ",
        "purpose" : "Esta es la descripción larga de la organizacion y es muy útil para describirla",
        "clasification": "ALM"
    });
};

Add 'clasification' in demo organization information


/* @flow */

const logger = require('../../logger')
const log = logger({
  component: 'scanFolder'
})

/*::
import type Buffer from './buffer'
import type { Producer } from './producer'
*/

// This step
module.exports = function (buffer /*: Buffer */, opts /*: { producer: Producer } */) /*: Buffer */ {
  return buffer.asyncMap(async (batch) => {
    for (const event of batch) {
      if (event.action === 'created' && event.kind === 'directory') {
        opts.producer.scan(event.path)
          .catch((err) => log.info({err, event}, 'Error on scan'))
      }
    }
    return batch
  })
}

/* @flow */

const logger = require('../../logger')
const log = logger({
  component: 'scanFolder'
})

/*::
import type Buffer from './buffer'
import type { Producer } from './producer'
*/

// When a directory that was not in the synchronized dir is moved to it,
// atom/Watcher emits a single event for the added directory. In this step,
// when this happens, we scan the directory to see if it contains files and
// sub-directories.
module.exports = function (buffer /*: Buffer */, opts /*: { producer: Producer } */) /*: Buffer */ {
  return buffer.asyncMap(async (batch) => {
    for (const event of batch) {
      if (event.action === 'created' && event.kind === 'directory') {
        opts.producer.scan(event.path)
          .catch((err) => log.info({err, event}, 'Error on scan'))
      }
    }
    return batch
  })
}

Add a comment to explain scanFolder


module.exports = function (context, req) {
    context.log('Node.js HTTP trigger function processed a request. Name=' + req.query.name);

    if (typeof req.query.name == 'undefined') {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string"
        }
    }
    else {
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + req.query.name
        }
    }
    context.done();
}

module.exports = function (context, req) {
    context.log('Node.js HTTP trigger function processed a request. Name=' + req.originalUrl);

    if (typeof req.query.name == 'undefined') {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string"
        }
    }
    else {
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + req.query.name
        }
    }
    context.done();
}

Use URI instead of query string


'use strict';

const { spawn } = require('child_process');

const PluginError = require('plugin-error');

// Execute a shell command
const execCommand = function (command) {
  const [commandA, ...args] = command.trim().split(/ +/);
  const child = spawn(commandA, args, { stdio: 'inherit' });

  // eslint-disable-next-line promise/avoid-new
  return new Promise(execCommandPromise.bind(null, child));
};

const execCommandPromise = function (child, resolve, reject) {
  child.on('exit', execCommandExit.bind(null, resolve, reject));
};

const execCommandExit = function (resolve, reject, exitCode) {
  if (exitCode === 0) { return resolve(); }

  const error = new PluginError('shell', 'Shell command failed');
  reject(error);
};

module.exports = {
  execCommand,
};

'use strict';

const { env } = require('process');
const { spawn } = require('child_process');

const PluginError = require('plugin-error');

// Execute a shell command
const execCommand = function (command) {
  const [commandA, ...args] = command.trim().split(/ +/);
  const envA = getEnv();
  const child = spawn(commandA, args, { stdio: 'inherit', env: envA });

  // eslint-disable-next-line promise/avoid-new
  return new Promise(execCommandPromise.bind(null, child));
};

// Adds local Node modules binary to `$PATH`
const getEnv = function () {
  const PATH = getPath({ env });
  const envA = { ...env, PATH };
  return envA;
};

const getPath = function ({ env: { PATH = '' } }) {
  const hasLocalDir = PATH.split(':').includes(LOCAL_NODE_BIN_DIR);
  if (hasLocalDir) { return PATH; }

  return `${PATH}:${LOCAL_NODE_BIN_DIR}`;
};

const LOCAL_NODE_BIN_DIR = './node_modules/.bin/';

// Check command exit code
const execCommandPromise = function (child, resolve, reject) {
  child.on('exit', execCommandExit.bind(null, resolve, reject));
};

const execCommandExit = function (resolve, reject, exitCode) {
  if (exitCode === 0) { return resolve(); }

  const error = new PluginError('shell', 'Shell command failed');
  reject(error);
};

module.exports = {
  execCommand,
};

Fix ./node_modules/.bin not being in $PATH for Gulp


// Game Controller
// A checkers board has 64 squares like a chess board but it only uses 32 squares all the same color
// Each player has 12 pieces and pieces that make until the last squares on the enemy side is promoted
// Promoted piece also moves on diagonals with no limit of squares if it is free
// The moves are on diagonal one square at a time
// To capture, the piece capturing jumps the enemy piece advancing two squares on diagonal
// The game end when one of the player lost all pieces or doesn't have moves to make
function Game() {
  /* Board.initial generate all elements used to be pieces and empty squares on the
  board and return an array of the board initial position*/
  this.board = Board.initial();
  this.player = "blue";
}

// flattenBoard ask the Board to flatten the current game board
Game.prototype.flattenBoard = function(){
  return Board.flatten(this.board);
}

Game.prototype.selectPiece = function(element){
  console.log(element);

}

// Game Controller
// A checkers board has 64 squares like a chess board but it only uses 32 squares all the same color
// Each player has 12 pieces and pieces that make until the last squares on the enemy side is promoted
// Promoted piece also moves on diagonals with no limit of squares if it is free
// The moves are on diagonal one square at a time
// To capture, the piece capturing jumps the enemy piece advancing two squares on diagonal
// The game end when one of the player lost all pieces or doesn't have moves to make
function Game() {
  /* Board.initial generate all elements used to be pieces and empty squares on the
  board and return an array of the board initial position*/
  this.board = Board.initial();
  this.flattenBoard = Board.flatten(this.board);
  this.player = "blue";
}

Game.prototype.selectPiece = function(element){
  console.log(element);
  console.log(this.flattenBoard);
}

Delete flattenBoard prototype and initialize flattenBoard as a variable


var assert = require('../lib/assertTheUnexpected');
var expect = require('unexpected');

describe('assertTheUnexpected', function () {
  describe('deepEqual', function () {
    it('should compare objects with loosely equal property (lhs)', function () {
      expect(function () {
        assert.deepEqual({ a: 1 }, { a: '1' });
      }, 'not to error');
    });

    it('should compare objects with loosely equal property (rhs)', function () {
      expect(function () {
        assert.deepEqual({ a: '1' }, { a: 1 });
      }, 'not to error');
    });

    it('should compare objects with loosely equal array (lhs)', function () {
      expect(function () {
        assert.deepEqual({ a: [1] }, { a: ['1'] });
      }, 'not to error');
    });

    it('should compare objects with loosely equal array (rhs)', function () {
      expect(function () {
        assert.deepEqual({ a: ['1'] }, { a: [1] });
      }, 'not to error');
    });
  });

  describe('doesNotThrow', function () {
    it('', function () {
      expect(function () {
        assert.doesNotThrow(function () { throw new Error('boo'); });
      }, 'to error', 'Got unwanted exception..');
    });
  });
});

var assert = require('../lib/assertTheUnexpected');
var expect = require('unexpected');

describe('assertTheUnexpected', function () {
  describe('deepEqual', function () {
    it('should compare objects with loosely equal property (lhs)', function () {
      expect(function () {
        assert.deepEqual({ a: 1 }, { a: '1' });
      }, 'not to error');
    });

    it('should compare objects with loosely equal property (rhs)', function () {
      expect(function () {
        assert.deepEqual({ a: '1' }, { a: 1 });
      }, 'not to error');
    });

    it('should compare objects with loosely equal array (lhs)', function () {
      expect(function () {
        assert.deepEqual({ a: [1] }, { a: ['1'] });
      }, 'not to error');
    });

    it('should compare objects with loosely equal array (rhs)', function () {
      expect(function () {
        assert.deepEqual({ a: ['1'] }, { a: [1] });
      }, 'not to error');
    });
  });

  describe('doesNotThrow', function () {
    it('', function () {
      expect(function () {
        assert.doesNotThrow(function () { throw new Error('boo'); });
      }, 'to error', 'Got unwanted exception..');
    });

    it('', function () {
      expect(function () {
        assert.doesNotThrow(function () { throw new Error('boo'); }, 'hoo');
      }, 'to error', 'Got unwanted exception. hoo');
    });
  });
});

Check the unwated exception string case.


var gulp = require("gulp");
var sass = require("gulp-sass");

gulp.task('sass', function () {
    gulp.src('src/hipster-grid-system.scss')
        .pipe(sass({
            // includePaths: require('node-bourbon').with('other/path', 'another/path')
            // - or -
            includePaths: require('node-bourbon').includePaths
        }))
        .pipe(gulp.dest('dist'));
});

var gulp = require("gulp");
var sass = require("gulp-sass");

gulp.task('sass', function () {
    gulp.src('src/hipster-grid-system.scss')
        .pipe(sass())
        .pipe(gulp.dest('dist'));
});

Remove bourbon options for new version


import {shortTitle} from '../../configs/general';
import slideIdTypeError from '../error/slideIdTypeError';
import { AllowedPattern } from '../error/util/allowedPattern';
import expandContentPanel from '../deckpagelayout/expandContentPanel';
import serviceUnavailable from '../error/serviceUnavailable';
const log = require('../log/clog');

export default function loadSlideEdit(context, payload, done) {
    if (!(AllowedPattern.SLIDE_ID.test(payload.params.sid) || payload.params.sid === undefined)) {
        context.executeAction(slideIdTypeError, payload, done);
        return;
    }

    context.service.read('slide.content', payload, {timeout: 20 * 1000}, (err, res) => {
        if (err) {
            log.error(context, {filepath: __filename, err: err});
            context.executeAction(serviceUnavailable, payload, done);
            //context.dispatch('LOAD_SLIDE_EDIT_FAILURE', err);
        } else {
            //expand edit view collapsing TreeNode. Then dispatch LOAD_SLIDE_EDIT_SUCCESS
            context.executeAction(expandContentPanel,{}, () => {
                context.dispatch('LOAD_SLIDE_EDIT_SUCCESS', res);
            });

            //TODO: do not allow editing title when on the edit slide mode
            //context.dispatch('UNDO_RENAME_TREE_NODE_SUCCESS', payload.params);
        }
        let pageTitle = shortTitle + ' | Slide Edit | ' + payload.params.sid;
        context.dispatch('UPDATE_PAGE_TITLE', {
            pageTitle: pageTitle
        });
        done();
    });
}

import {shortTitle} from '../../configs/general';
import slideIdTypeError from '../error/slideIdTypeError';
import { AllowedPattern } from '../error/util/allowedPattern';
import expandContentPanel from '../deckpagelayout/expandContentPanel';
import serviceUnavailable from '../error/serviceUnavailable';
const log = require('../log/clog');

export default function loadSlideEdit(context, payload, done) {
    if (!(AllowedPattern.SLIDE_ID.test(payload.params.sid) || payload.params.sid === undefined)) {
        context.executeAction(slideIdTypeError, payload, done);
        return;
    }

    context.service.read('slide.content', payload, {timeout: 20 * 1000}, (err, res) => {
        if (err) {
            log.error(context, {filepath: __filename, err: err});
            context.executeAction(serviceUnavailable, payload, done);
            //context.dispatch('LOAD_SLIDE_EDIT_FAILURE', err);
        } else {
            //expand edit view collapsing TreeNode. Then dispatch LOAD_SLIDE_EDIT_SUCCESS
            //revert for SWIK-1347 - Slide Edit view to display decktree (and right-hand panel)
            //context.executeAction(expandContentPanel,{}, () => {
            context.dispatch('LOAD_SLIDE_EDIT_SUCCESS', res);
            //});

            //TODO: do not allow editing title when on the edit slide mode
            //context.dispatch('UNDO_RENAME_TREE_NODE_SUCCESS', payload.params);
        }
        let pageTitle = shortTitle + ' | Slide Edit | ' + payload.params.sid;
        context.dispatch('UPDATE_PAGE_TITLE', {
            pageTitle: pageTitle
        });
        done();
    });
}

Remove call to expandContentPanel action on slide edit URL/load


'use strict';

var contentful = require('..');
var q = require('q');

if (process.env.CONTENTFUL_ACCESS_TOKEN === undefined) {
    throw new ReferenceError('Environment variable must be defined: CONTENTFUL_ACCESS_TOKEN');
}
if (process.env.CONTENTFUL_MANAGEMENT_HOSTNAME === undefined) {
    throw new ReferenceError('Environment variable must be defined: CONTENTFUL_MANAGEMENT_HOSTNAME');
}
exports.client = contentful.createClient({
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
  host: process.env.CONTENTFUL_MANAGEMENT_HOSTNAME,
  secure: false
});

exports.wait = wait;
function wait(ms) {
  if (!ms) { ms = 5000; }
  return q.delay(ms);
}

'use strict';

var contentful = require('..');
var q = require('q');

if (process.env.CONTENTFUL_ACCESS_TOKEN === undefined) {
    throw new ReferenceError('Environment variable must be defined: CONTENTFUL_ACCESS_TOKEN');
}
if (process.env.CONTENTFUL_MANAGEMENT_HOSTNAME === undefined) {
    throw new ReferenceError('Environment variable must be defined: CONTENTFUL_MANAGEMENT_HOSTNAME');
}
exports.client = contentful.createClient({
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
  host: process.env.CONTENTFUL_MANAGEMENT_HOSTNAME,
  secure: true
});

exports.wait = wait;
function wait(ms) {
  if (!ms) { ms = 5000; }
  return q.delay(ms);
}

Enable SSL by default in client used for testing


'use strict';

var gulp = require('gulp');

gulp.task('watch', ['jade', 'wiredep', 'styles'], function () {
  gulp.watch('app/styles/**/*.sass', ['styles']);
  gulp.watch('app/scripts/**/*.js', ['scripts']);
  gulp.watch('app/images/**/*', ['images']);
  gulp.watch('bower.json', ['wiredep']);

  gulp.start('watch:jade');
});

'use strict';

var gulp = require('gulp');

gulp.task('watch', ['jade', 'wiredep', 'styles'], function () {
  gulp.watch('app/styles/**/*.sass', ['styles']);
  gulp.watch('bower.json', ['wiredep']);

  gulp.start('watch:jade');
});

Remove other irrelevant steps from gulp serve.


#!/usr/bin/env node

// This script prints out the absolute path to the emcc wrapper script in
// this directory. node-gyp make_global_settings CXX and LINK require
// absolute paths to the compiler.

process.stdout.write(require.resolve('nbind/bin/emcc'));

#!/usr/bin/env node

// This script prints out the absolute path to the emcc wrapper script in
// this directory. node-gyp make_global_settings CXX and LINK require
// absolute paths to the compiler.

process.stdout.write(require('path').resolve(__dirname, 'emcc'));

Fix loading asm.js code without running "npm link nbind".


#!/usr/bin/env node

/*eslint no-console: 0*/

'use strict';

const cli = require('../lib/support/cli'),
  sitespeed = require('../lib/sitespeed'),
  Promise = require('bluebird');

if (process.env.NODE_ENV !== 'production') {
  require('longjohn');
}

Promise.config({
  warnings: true,
  longStackTraces: true
});

process.exitCode = 1;

let parsed = cli.parseCommandLine();
let budgetFailing = false;
// hack for getting in the unchanged cli options
parsed.options.explicitOptions = parsed.explicitOptions;
parsed.options.urls = parsed.urls;
parsed.options.urlsMetaData = parsed.urlsMetaData;

return sitespeed.run(parsed.options)
  .then((result) => {
    if (result.errors.length > 0) {
      throw new Error('Errors while running:\n' + result.errors.join('\n'));
    }
    if (parsed.options.budget && Object.keys(result.budgetResult.failing).length > 0) {
      process.exitCode = 1;
      budgetFailing = true;
    }
  })
  .then(() => {
    if (!budgetFailing) {
      process.exitCode = 0;
    }
  })
  .catch(() => {
    process.exitCode = 1;
  })
  .finally(() => process.exit());

#!/usr/bin/env node

/*eslint no-console: 0*/

'use strict';

const cli = require('../lib/support/cli'),
  sitespeed = require('../lib/sitespeed'),
  Promise = require('bluebird');

if (process.env.NODE_ENV !== 'production') {
  require('longjohn');
}

Promise.config({
  warnings: true,
  longStackTraces: true
});

process.exitCode = 1;

let parsed = cli.parseCommandLine();
let budgetFailing = false;
// hack for getting in the unchanged cli options
parsed.options.explicitOptions = parsed.explicitOptions;
parsed.options.urls = parsed.urls;
parsed.options.urlsMetaData = parsed.urlsMetaData;

sitespeed
  .run(parsed.options)
  .then(result => {
    if (result.errors.length > 0) {
      throw new Error('Errors while running:\n' + result.errors.join('\n'));
    }
    if (
      parsed.options.budget &&
      Object.keys(result.budgetResult.failing).length > 0
    ) {
      process.exitCode = 1;
      budgetFailing = true;
    }
  })
  .then(() => {
    if (!budgetFailing) {
      process.exitCode = 0;
    }
  })
  .catch(() => {
    process.exitCode = 1;
  })
  .finally(() => process.exit());

Fix syntax error (return outside function).


/**
A utility to attach a tooltip to a DOM element.

@submodule utils
@method renderTooltip
@param {Element} domElement The DOM element, not jQuery element, to attach the tooltip to
@param {Object} options The tooltip options to render the tooltip with. For supported options, see the tooltipSupportedProperties array in the views initializer
*/

import Ember from 'ember';

const Tooltip = window.Tooltip;

export default function renderTooltip(domElement = {}, options = {}) {
  const typeClass = options.typeClass;

  let tooltip;

  Ember.assert('You must pass a DOM element as the first argument to the renderTooltip util', !!domElement.tagName);

  if (typeClass) {
    options.typeClass = 'tooltip-' + typeClass;
  }

  if (!options.event) {
    options.event = 'hover';
  }

  tooltip = new Tooltip(options.content, options);

  tooltip.attach(domElement);

  if (options.event !== 'manual') {
    Ember.$(domElement)[options.event](function() {
      const willShow = tooltip.hidden;

      tooltip.toggle();

      // Clean previously queued removal (if present)
      Ember.run.cancel(tooltip._hideTimer);
      if (willShow && options.duration) {
        // Hide tooltip after specified duration
        let hideTimer = Ember.run.later(function() {
          tooltip.hide();
        }, options.duration);
        // Save timer id for cancelling
        tooltip._hideTimer = hideTimer;
      }
    });
  }

  return tooltip;
}

/**
A utility to attach a tooltip to a DOM element.

@submodule utils
@method renderTooltip
@param {Element} domElement The DOM element, not jQuery element, to attach the tooltip to
@param {Object} options The tooltip options to render the tooltip with. For supported options, see the tooltipSupportedProperties array in the views initializer
*/

import Ember from 'ember';

const Tooltip = window.Tooltip;

export default function renderTooltip(domElement = {}, options = {}) {
  const typeClass = options.typeClass;

  let tooltip;

  Ember.assert('You must pass a DOM element as the first argument to the renderTooltip util', !!domElement.tagName);

  if (typeClass) {
    options.typeClass = 'tooltip-' + typeClass;
  }

  if (!options.event) {
    options.event = 'hover';
  }

  if (options.duration && typeof options.duration === 'string') {
    options.duration = parseInt(options.duration, 10);
    if (isNaN(options.duration) || !isFinite(options.duration)) {
      // Remove invalid parseInt results
      options.duration = null;
    }
  }

  tooltip = new Tooltip(options.content, options);

  tooltip.attach(domElement);

  if (options.event !== 'manual') {
    Ember.$(domElement)[options.event](function() {
      const willShow = tooltip.hidden;

      tooltip.toggle();

      // Clean previously queued removal (if present)
      Ember.run.cancel(tooltip._hideTimer);
      if (willShow && options.duration) {
        // Hide tooltip after specified duration
        let hideTimer = Ember.run.later(function() {
          tooltip.hide();
        }, options.duration);
        // Save timer id for cancelling
        tooltip._hideTimer = hideTimer;
      }
    });
  }

  return tooltip;
}

Allow duration to be provided as a string


'use strict';

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

var paths = {
    js: ['./gulpfile.js', './test/**/*.js'],
    scss: ['./stylesheets/_sass-lib.scss'],
    test: './test/**/*.js'
};

var plumberOpts = {};

gulp.task('js-lint', function() {
    return gulp.src(paths.js)
        .pipe($.jshint('.jshintrc'))
        .pipe($.plumber(plumberOpts))
        .pipe($.jscs())
        .pipe($.jshint.reporter('jshint-stylish'));
});

gulp.task('scss-lint', function() {
    gulp.src(paths.scss)
        .pipe($.scssLint())
        .pipe($.plumber(plumberOpts));
});

gulp.task('test', function() {
    return gulp.src(paths.test, {read: false})
        .pipe($.mocha({reporter: 'min'}));
});

gulp.task('lint', ['scss-lint', 'js-lint']);

gulp.task('watch', 'test', function() {
    gulp.watch(paths.js, 'js-lint');
    gulp.watch(paths.scss, 'scss-lint');
    gulp.watch(paths.test, 'test');
});

gulp.task('default', ['scss-lint', 'js-lint', 'test']);

'use strict';

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

var paths = {
    js: ['./gulpfile.js', './test/**/*.js'],
    scss: ['./stylesheets/_sass-lib.scss'],
    test: './test/**/*.js'
};

var plumberOpts = {};

gulp.task('js-lint', function() {
    return gulp.src(paths.js)
        .pipe($.jshint('.jshintrc'))
        .pipe($.plumber(plumberOpts))
        .pipe($.jscs())
        .pipe($.jshint.reporter('jshint-stylish'));
});

gulp.task('scss-lint', function() {
    gulp.src(paths.scss)
        .pipe($.scssLint())
        .pipe($.plumber(plumberOpts));
});

gulp.task('test', function() {
    return gulp.src(paths.test, {read: false})
        .pipe($.mocha({reporter: 'min'}));
});

gulp.task('lint', ['scss-lint', 'js-lint']);

gulp.task('watch', ['test'], function() {
    gulp.watch(paths.js, 'js-lint');
    gulp.watch(paths.scss, 'scss-lint');
    gulp.watch(paths.test, 'test');
});

gulp.task('default', ['scss-lint', 'js-lint', 'test']);

Fix bug in watch task