import React, { PropTypes } from 'react'
import { connect } from 'react-redux'

// Global module dependencies
import { SettingsPageLayout } from '../../../components/Layout'

// Parent module dependencies
import * as MobilizationSelectors from '../../mobilizations/selectors'

// Current module dependencies
import * as WidgetSelectors from '../selectors'

export const SettingsContainer = ({ children, ...rest }) => (
  <SettingsPageLayout>
    {children && React.cloneElement(children, {...rest})}
  </SettingsPageLayout>
)

SettingsContainer.propTypes = {
  children: PropTypes.object,
  mobilization: PropTypes.object.isRequired,
  widget: PropTypes.object.isRequired,
  widgets: PropTypes.array.isRequired
}

const mapStateToProps = (state, props) => ({
  mobilization: MobilizationSelectors.getCurrent(state, props),
  widget: WidgetSelectors.getWidget(state, props),
  widgets: WidgetSelectors.getList(state)
})

export default connect(mapStateToProps)(SettingsContainer)

import React, { PropTypes } from 'react'
import { connect } from 'react-redux'

// Global module dependencies
import { SettingsPageLayout } from '../../../components/Layout'

// Parent module dependencies
import * as MobilizationSelectors from '../../mobilizations/selectors'

// Current module dependencies
import * as WidgetSelectors from '../selectors'

export const SettingsContainer = ({ children, ...rest }) => (
  <SettingsPageLayout>
    {children && React.cloneElement(children, {...rest})}
  </SettingsPageLayout>
)

SettingsContainer.propTypes = {
  children: PropTypes.object,
  mobilization: PropTypes.object.isRequired,
  widget: PropTypes.object.isRequired,
  widgets: PropTypes.array.isRequired
}

const mapStateToProps = (state, props) => ({
  mobilization: MobilizationSelectors.getCurrent(state),
  widget: WidgetSelectors.getWidget(state, props),
  widgets: WidgetSelectors.getList(state)
})

export default connect(mapStateToProps)(SettingsContainer)

Remove props param to get current mobilization selector


function fileToArray(file) {
  return (
    fs.readFileSync(__dirname + '/' +file)
      .toString()
      .trim()
      .split('\n')
  );
}

const sandwich = require('sandwich');
const fs = require('fs');
const ADVERBS = fileToArray('adverbs.txt');
const ADJECTIVES = fileToArray('adjectives.txt');
const NOUNS = fileToArray('nouns.txt');
const iterator = sandwich(ADVERBS, ADJECTIVES, NOUNS);

function phrases(count) {
  const matches = {};
  const results = [];
  var length = 0;
  var word;
  while (length < count) {
    word = iterator.random().join('-');
    if (!matches[word]) {
      matches[word] = results.push(word);
      length++;
    }
  }
  return results;
};
phrases.iterator = iterator;
module.exports = phrases;

const path = require('path');
const sandwich = require('sandwich');
const fs = require('fs');

function fileToArray(file) {
  return (
    fs.readFileSync(path.join(__dirname, '/', file))
      .toString()
      .trim()
      .split('\n')
  );
}

const ADVERBS = fileToArray('adverbs.txt');
const ADJECTIVES = fileToArray('adjectives.txt');
const NOUNS = fileToArray('nouns.txt');
const iterator = sandwich(ADVERBS, ADJECTIVES, NOUNS);

function phrases(count) {
  const matches = {};
  const results = [];
  var length = 0;
  var word;
  while (length < count) {
    word = iterator.random().join('-');
    if (!matches[word]) {
      matches[word] = results.push(word);
      length++;
    }
  }
  return results;
}

phrases.iterator = iterator;
module.exports = phrases;

Use path.join instead of concating directories.


Fix logoBig drawing over nav overlay


module.exports = {
  getAccountModel: function (redisClient, accountHashID, callback) {

  }
}

var configuration = require('../../config/configuration.json')

module.exports = {
  getAccountModel: function (redisClient, accountHashID, callback) {
    var tableName = configuration.TableMAAccountModelAnnouncerAccountModel + accountHashID
    redisClient.hmget(tableName,
      configuration.ConstantAMAAMBudget,
      configuration.ConstantAMAAMAccountType,
      function (err, replies) {
        if (err) {
          callback(err, null)
          return
        }
        callback(null, replies)
      }
    )
  }
}

Implement Get AccountModel Business Logic


'use strict'

const gulp = require('gulp')
const watch = require('gulp-watch')
const pug = require('gulp-pug')
const scss = require('gulp-sass')
const prefix = require('gulp-autoprefixer')

const dev = 'src'
const server = 'dist'

const build_html = function() {
    return gulp.src(dev + '/pug/*.pug')
        .pipe(pug({pretty: true}))
        .pipe(gulp.dest(server));
}

const build_css = function() {
    return gulp.src(dev+'/scss/*.scss')
        .pipe(scss())
        .pipe(prefix())
        .pipe(gulp.dest(server+'/css'));
}

gulp.task('watch', function() {
    watch(dev+'/pug/*.pug', build_html);
    watch(dev+'/scss/**/*.scss', build_css);
});

gulp.task('build_html', build_html);
gulp.task('build_css', build_css);

'use strict'

const gulp = require('gulp')
const watch = require('gulp-watch')
const pug = require('gulp-pug')
const scss = require('gulp-sass')
const prefix = require('gulp-autoprefixer')

const dev = 'src'
const server = 'dist'

const build_html = function() {
    return gulp.src(dev + '/pug/*.pug')
        .pipe(pug({pretty: true}))
        .pipe(gulp.dest(server));
}

const build_css = function() {
    return gulp.src(dev+'/scss/*.scss')
        .pipe(scss())
        .pipe(prefix())
        .pipe(gulp.dest(server+'/css'));
}

gulp.task('watch', function() {
    // watch(dev+'/pug/*.pug', build_html);
    watch(dev+'/scss/**/*.scss', build_css);
});

gulp.task('build_html', build_html);
gulp.task('build_css', build_css);

Disable pug compiling from watch. The pug compiler is crashing on node 10


var gulp = require('gulp'),
    exec = require('child_process').exec;

gulp.task('test', function(cb) {
    exec(
		'node testrunner.js',
		{ cwd : 'tests' },
		function (err, stdout, stderr) {
			console.log(stdout);
			console.log(stderr);
			cb(err);
		}
	);
});

gulp.task('default', function() {
    gulp.watch(['**/*.js', 'tests/tests.json'], ['test']);
});

var gulp = require("gulp");
var exec = require("child_process").exec;

gulp.task("test", function(cb) {
  exec(
    "node testrunner.js",
    {cwd: "tests"},
    function(err, stdout, stderr) {
      console.log(stdout);
      console.log(stderr);
      cb(err);
    }
  );
});

gulp.task("default", function() {
  gulp.watch(["**/*.js", "tests/tests.json"], ["test"]);
});

Add an eslint config and update the code to match it.


// gulpfile.js

// Packages
var gulp = require('gulp');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');

// Tasks

// Uglify
gulp.task('games-js', function(){

    return gulp
        .src('resources/assets/js/games/index.js')
        //.pipe(rename('index.min.js'))
        .pipe(rename({suffix: '.min'}))
        .pipe(uglify())
        .pipe(gulp.dest('public/js/games'));

});

// Browserify & Babel
gulp.task('users-js', function(){

    return browserify('resources/assets/js/users/index.js')
        .transform('babelify', {presets: ['es2015']})
        .bundle()
        .pipe(source('user-bundle.min.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('public/js/users'));

});

// gulpfile.js

// Packages
var gulp = require('gulp');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');

// Tasks

var bundleGames = function() {

    return gulp
        .src('resources/assets/js/games/index.js')
        //.pipe(rename('index.min.js'))
        .pipe(rename({suffix: '.min'}))
        .pipe(uglify())
        .pipe(gulp.dest('public/js/games'));

}

var bundleUsers = function() {

    return browserify('resources/assets/js/users/index.js')
        .transform('babelify', {presets: ['es2015']})
        .bundle()
        .pipe(source('user-bundle.min.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('public/js/users'));

}

// Uglify
gulp.task('games-js', function(){
    return bundleUsers();
});

// Browserify & Babel
gulp.task('users-js', function(){
    return bundleUsers();
});

Refactor Gulpfile for Gulp Watch


var gulp    = require('gulp');
var phpunit = require('gulp-phpunit');
var phplint = require('gulp-phplint');
var watch = require('gulp-watch');
var notifier = require('node-notifier');
var debug = require('gulp-debug');

var map = ['src/*.php', 'tests/*.php'];

gulp.task('dev', function(cb) {
    var options = {
      debug:             true,
      statusLine:        true,
      configurationFile: './build/phpunit.xml'
    };

    watch(map, function() {
        gulp
            .src(map)
            .pipe(phplint(''))
            .pipe(phplint.reporter(function (file) {
                var report = file.phplintReport || {};
                if (report.error) {
                    /*notifier.notify({
                        'title': 'PhpLint',
                        'Message': 'Lint failed'
                    });*/
                }
            }))
            .pipe(phpunit('./vendor/bin/phpunit', options))

            .on('end', cb);
    })

});

var gulp    = require('gulp');
var phpunit = require('gulp-phpunit');
var phplint = require('gulp-phplint');
var watch = require('gulp-watch');
var notifier = require('node-notifier');
var debug = require('gulp-debug');

var map = ['src/**/*.php', 'tests/**/*.php'];

gulp.task('dev', function(cb) {
    var options = {
      debug:             true,
      statusLine:        true,
      configurationFile: './build/phpunit.xml'
    };

    watch(map, function() {
        gulp
            .src(map)
            .pipe(phplint(''))
            .pipe(phplint.reporter(function (file) {
                var report = file.phplintReport || {};
                if (report.error) {
                    /*notifier.notify({
                        'title': 'PhpLint',
                        'Message': 'Lint failed'
                    });*/
                }
            }))
            .pipe(phpunit('./vendor/bin/phpunit', options))

            .on('end', cb);
    })

});

Update gulp paths to scan recusrively


import React, {View, Text, Linking} from 'react-native'

import {logout} from '../api/Account'
import Styles from '../styles/Styles'
import ControlPanelItem from '../components/ControlPanelItem'
import Settings from '../settings'

export default React.createClass({
  render() {
    return (
      <View style={Styles.controlPanel.container}>
        <ControlPanelItem
          onPress={()=>{
            this.props.closeDrawer();
            this.props.logout();
          }}
          text="Logout"
        />
        <ControlPanelItem
          onPress={()=>{
            this.props.navigator.push({name: 'surveylist'})
            this.props.closeDrawer()
          }}
          text="Surveys"
        />
        <ControlPanelItem
          text="Notifications"
        />
        <ControlPanelItem
          text="Profile"
        />
        <ControlPanelItem
          text="Account"
        />
        <ControlPanelItem
          onPress={()=>{
            // mailto links do not work in the ios simulator.
            // https://github.com/facebook/react-native/issues/916
            // TODO: Set up support mailing list
            Linking.openURL("mailto:goodquestion@ecohealthalliance.org?subject=Support")
              .catch(err => console.error('An error occurred', err))
            this.props.closeDrawer()
          }}
          text="Support"
        />
        <View style={Styles.controlPanel.item}>
            <Text>Version: {Settings.version || "None"}</Text>
        </View>
      </View>
    )
  }
})

import React, {View, Text, Linking} from 'react-native'

import {logout} from '../api/Account'
import Styles from '../styles/Styles'
import ControlPanelItem from '../components/ControlPanelItem'
import Settings from '../settings'

export default React.createClass({
  render() {
    return (
      <View style={Styles.controlPanel.container}>
        <ControlPanelItem
          onPress={()=>{
            this.props.closeDrawer();
            this.props.logout();
          }}
          text="Logout"
        />
        <ControlPanelItem
          onPress={()=>{
            this.props.navigator.push({name: 'surveylist', title: "Surveys"})
            this.props.closeDrawer()
          }}
          text="Surveys"
        />
        <ControlPanelItem
          text="Notifications"
        />
        <ControlPanelItem
          text="Profile"
        />
        <ControlPanelItem
          text="Account"
        />
        <ControlPanelItem
          onPress={()=>{
            // mailto links do not work in the ios simulator.
            // https://github.com/facebook/react-native/issues/916
            // TODO: Set up support mailing list
            Linking.openURL("mailto:goodquestion@ecohealthalliance.org?subject=Support")
              .catch(err => console.error('An error occurred', err))
            this.props.closeDrawer()
          }}
          text="Support"
        />
        <View style={Styles.controlPanel.item}>
            <Text>Version: {Settings.version || "None"}</Text>
        </View>
      </View>
    )
  }
})

Send title to navigator on control panel item press


var MIM = angular.module('starter.services', []);

MIM.factory('DB', function($q, $ionicPlatform, $cordovaSQLite) {
  this.queryStatement = function(query, parameters) {
    parameters = parameters || [];
    var q = $q.defer();

    $ionicPlatform.ready(function() {
      $cordovaSQLite.execute(db, query, parameters).then(function(res) {
        q.resolve(res);
      }, function(error) {
        console.error(error);
        q.reject(error);
      });
    });

    return q.promise;
  };
});

var MIM = angular.module('starter.services', []);

MIM.factory('DB', function($q, $ionicPlatform, $cordovaSQLite) {
  this.queryStatement = function(query, parameters) {
    parameters = parameters || [];
    var q = $q.defer();

    $ionicPlatform.ready(function() {
      $cordovaSQLite.execute(db, query, parameters).then(function(res) {
        q.resolve(res);
      }, function(error) {
        console.error(error);
        q.reject(error);
      });
    });

    return q.promise;
  };

  this.getAll = function(res) {
    var output = [];

    if (res.rows.length) {
      for (var i = 0; i < res.rows.length; i++) {
        output.push(res.rows.item(i));
      }
    }

    return output;
  };

  this.getById = function(res) {
    var output = null;

    if (res.rows.length) {
      angular.copy(output, res.rows.item(0));
    }

    return output;
  }

  return this;
});

Add global query function getAll and getById


'use strict';

import Fabric from '../';

const assert = require('assert');
const expect = require('chai').expect;

const widget = require('../data/widget');

describe('Resource', function () {
  it('should expose a constructor', function () {
    assert.equal(typeof Fabric.Resource, 'function');
  });

  it('should initialize a known Resource', async function () {
    let resource = new Fabric.Resource(widget);
    let store = new Fabric.Store();

    await store.open();

    try {
      resource.trust(store);
      let test = await resource.create({
        name: 'Wobbler'
      });

      assert.ok(test);
    } catch (E) {
      console.error(E);
    }

    await store.close();
  });
});

'use strict';

import Fabric from '../';

const assert = require('assert');
const expect = require('chai').expect;

const widget = require('../data/widget');

describe('Resource', function () {
  it('should expose a constructor', function () {
    assert.equal(typeof Fabric.Resource, 'function');
  });

  it('should initialize a known Resource', async function () {
    let resource = new Fabric.Resource(widget);
    let store = new Fabric.Store();

    await store.open();

    try {
      resource.trust(store);
      let test = await resource.create({
        name: 'Wobbler'
      });

      assert.ok(test);
    } catch (E) {
      console.error(E);
    }

    await store.close();
  });

  it('should call query() smoothly', async function () {
    let resource = new Fabric.Resource(widget);
    let store = new Fabric.Store();

    await store.open();

    try {
      resource.trust(store);
      let test = await resource.create({
        name: 'Wobbler'
      });

      let results = await resource.query();

      assert.ok(test);
      assert.ok(results);

      assert.equal(results.length, 1);
    } catch (E) {
      console.error(E);
    }

    await store.close();
  });
});

Add query() test for Resource


class UrlBuilder {
    constructor(name, absolute, ziggyObject) {

        this.name = name;
        this.ziggy = ziggyObject;
        this.route = this.ziggy.namedRoutes[this.name];

        if (typeof this.name === 'undefined') {
            throw new Error('Ziggy Error: You must provide a route name');
        } else if (typeof this.route === 'undefined') {
            throw new Error(`Ziggy Error: route '${this.name}' is not found in the route list`);
        }

        this.absolute = typeof absolute === 'undefined' ? true : absolute;
        this.domain = this.setDomain();
        this.path = this.route.uri.replace(/^\//, '');
    }

    setDomain() {
        if (!this.absolute)
            return '/';

        if (!this.route.domain)
            return this.ziggy.baseUrl.replace(/\/?$/, '/');

        let host = (this.route.domain || this.ziggy.baseDomain).replace(/\/+$/, '');

        if (this.ziggy.basePort && (host.replace(/\/+$/, '') === this.ziggy.baseDomain.replace(/\/+$/, '')))
            host = this.ziggy.baseDomain + ':' + this.ziggy.basePort;

        return this.ziggy.baseProtocol + '://' + host + '/';
    }

    construct() {
        return this.domain + this.path
    }
}

export default UrlBuilder;

class UrlBuilder {
    constructor(name, absolute, ziggyObject) {

        this.name = name;
        this.ziggy = ziggyObject;
        this.route = this.ziggy.namedRoutes[this.name];

        if (typeof this.name === 'undefined') {
            throw new Error('Ziggy Error: You must provide a route name');
        } else if (typeof this.route === 'undefined') {
            throw new Error(`Ziggy Error: route '${this.name}' is not found in the route list`);
        }

        this.absolute = typeof absolute === 'undefined' ? true : absolute;
        this.domain = this.setDomain();
        this.path = this.route.uri.replace(/^\//, '');
    }

    setDomain() {
        if (!this.absolute)
            return '/';

        if (!this.route.domain)
            return this.ziggy.baseUrl.replace(/\/?$/, '/');

        let host = (this.route.domain || this.ziggy.baseDomain).replace(/\/+$/, '');

        if (this.ziggy.basePort) {
            host = `${host}:${this.ziggy.basePort}`;
        }

        return this.ziggy.baseProtocol + '://' + host + '/';
    }

    construct() {
        return this.domain + this.path
    }
}

export default UrlBuilder;

Remove check for matching base domain and update host string concatenation to *append* the port rather than reconstructing the whole string


/**
 * Copyright (c) 2013, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

exports.guessTabWidth = function(source) {
  var counts = []; // Sparse array.
  var lastIndent = 0;

  source.split("\n").forEach(function(line) {
    var indent = /^\s*/.exec(line)[0].length;
    var diff = Math.abs(indent - lastIndent);
    counts[diff] = ~~counts[diff] + 1;
    lastIndent = indent;
  });

  var maxCount = -1;
  var result = 2;

  for (var tabWidth = 1;
       tabWidth < counts.length;
       tabWidth += 1) {
    if (tabWidth in counts &&
        counts[tabWidth] > maxCount) {
      maxCount = counts[tabWidth];
      result = tabWidth;
    }
  }

  return result;
};

exports.defaults = function(obj) {
  var len = arguments.length;
  var extension;

  for (var i = 1; i < len; ++i) {
    if ((extension = arguments[i])) {
      for (var key in extension) {
        if (obj[key] === undefined) {
          obj[key] = extension[key];
        }
      }
    }
  }

  return obj;
};

/**
 * Copyright (c) 2013, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var hasOwn = Object.prototype.hasOwnProperty;

exports.guessTabWidth = function(source) {
  var counts = []; // Sparse array.
  var lastIndent = 0;

  source.split("\n").forEach(function(line) {
    var indent = /^\s*/.exec(line)[0].length;
    var diff = Math.abs(indent - lastIndent);
    counts[diff] = ~~counts[diff] + 1;
    lastIndent = indent;
  });

  var maxCount = -1;
  var result = 2;

  for (var tabWidth = 1;
       tabWidth < counts.length;
       tabWidth += 1) {
    if (tabWidth in counts &&
        counts[tabWidth] > maxCount) {
      maxCount = counts[tabWidth];
      result = tabWidth;
    }
  }

  return result;
};

exports.defaults = function(obj) {
  var len = arguments.length;
  var extension;

  for (var i = 1; i < len; ++i) {
    if ((extension = arguments[i])) {
      for (var key in extension) {
        if (hasOwn.call(extension, key) && !hasOwn.call(obj, key)) {
          obj[key] = extension[key];
        }
      }
    }
  }

  return obj;
};

Use hasOwnProperty when setting defaults


import MJMLElement from './decorators/MJMLElement'
import React, { Component } from 'react'

@MJMLElement({
  tagName: 'mj-raw'
})
class Raw extends Component {

  render () {
    const { mjContent } = this.props

    return (
      <tr
        className="mj-raw"
        dangerouslySetInnerHTML={{ __html: mjContent() }} />
    )
  }

}

export default Raw

import MJMLElement from './decorators/MJMLElement'
import React, { Component } from 'react'

@MJMLElement({
  tagName: 'mj-raw'
})
class Raw extends Component {

  getTagName () {
    const { parentMjml } = this.props
    let tagName

    switch (parentMjml.get('tagName')) {
      case 'mj-column' :
        tagName = 'tr'
        break

      default:
        tagName = 'noscript'
    }

    return tagName
  }

  render () {
    const { mjContent } = this.props

    return React.createElement(this.getTagName(), {
      className: 'mj-raw',
      dangerouslySetInnerHTML: { __html: mjContent() }
    })
  }

}

export default Raw

Fix tagName on mj-raw when parent is mj-column


(function(d) {
  var config = {
    kitId: 'kyi0gmx',
    scriptTimeout: 3000,
    async: true
  },
  h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='//use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
})(document);
jQuery(document).ready(function($) {
  $(".site-main-title").lettering('words');
  $(".site-sub-title").lettering('words');
});

Remove code that uses Lettering.js


const test = require('tap').test;
const Clock = require('../../src/io/clock');
const Runtime = require('../../src/engine/runtime');

test('spec', t => {
    const rt = new Runtime();
    const c = new Clock(rt);

    t.type(Clock, 'function');
    t.type(c, 'object');
    t.type(c.projectTimer, 'function');
    t.type(c.pause, 'function');
    t.type(c.resume, 'function');
    t.type(c.resetProjectTimer, 'function');
    t.end();
});

test('cycle', t => {
    const rt = new Runtime();
    const c = new Clock(rt);

    t.ok(c.projectTimer() <= 0.1);
    setTimeout(() => {
        c.resetProjectTimer();
        setTimeout(() => {
            // The timer shouldn't advance until all threads have been stepped
            t.ok(c.projectTimer() === 0);
            c.pause();
            t.ok(c.projectTimer() === 0);
            c.resume();
            t.ok(c.projectTimer() === 0);
            t.end();
        }, 100);
    }, 100);
    rt._step();
    t.ok(c.projectTimer() > 0);
});

test('reset on runtime dispose', t => {
    const rt = new Runtime();
    const c = rt.ioDevices.clock;
    let simulatedTime = 0;

    c._projectTimer = {
        timeElapsed: () => simulatedTime,
        start: () => {
            simulatedTime = 0;
        }
    };

    t.ok(c.projectTimer() === 0);
    simulatedTime += 1000;
    t.ok(c.projectTimer() === 1);
    rt.dispose();
    // When the runtime is disposed, the clock should be reset
    t.ok(c.projectTimer() === 0);
    t.end();
});

Test that clock is reset on runtime dispose


(function($) {

    jQuery.fn.comboEdit = function(options){
        options.selector = jQuery(this).selector;

        var onClick = function(e){

            var toBeReplaced = jQuery(this);

            var data = {};

            var parent_id = jQuery(this).parent().parent().find("."+options.parentIdClass).val();
            data.parent_id = parent_id;

            jQuery.get(options.getComboBoxURL, data, function(response){
                toBeReplaced.replaceWith(response);

                jQuery('option').click(function(){
                    var theValue = jQuery(this).val();
                    var toBeReplaced = jQuery(this).parent().parent();

                    data.id = theValue;

                    jQuery.post(options.submitURL, data, function(response){

                        toBeReplaced.replaceWith(response);

                        jQuery(options.selector).click(onClick);

                    }, 'html');

                });

            }, 'html');

        }

        return this.each(function(){
            jQuery(this).click(onClick);
        });
    }

})(jQuery);

(function($) {

    jQuery.fn.comboEdit = function(options){
        options.selector = jQuery(this).selector;

        var onClick = function(e){

            var toBeReplaced = jQuery(this);

            var data = {};

            var parent_id = jQuery(this).parent().parent().find("."+options.parentIdClass).val();
            data.parent_id = parent_id;

            jQuery.get(options.getComboBoxURL, data, function(response){
                toBeReplaced.replaceWith(response);

                jQuery('option').click(function(){
                    var theValue = jQuery(this).val();
                    var toBeReplaced = jQuery(this).parent().parent();

                    data.id = theValue;
                    data.child_id = theValue;
                    data.parent_id = parent_id;

                    jQuery.post(options.submitURL, data, function(response){

                        toBeReplaced.replaceWith(response);

                        jQuery(options.selector).click(onClick);

                    }, 'html');

                });

            }, 'html');

        }

        return this.each(function(){
            jQuery(this).click(onClick);
        });
    }

})(jQuery);

Add child_id params as well to prevent clash in some cases


$(document).ready(function(){

  // var turbolinks = require('turbolinks')

  $("#walk-me-home").on("click", function(e){
    e.preventDefault();

    $.ajax({
      url: "http://172.16.50.232:8080/start",
      crossDomain : true,
    })
    .done(function(serverResponse){
      $("#walk-me-home").hide();
      $("#home-safely").show();
      console.log(serverResponse + "This is the server response");
    })
  // need to add failure response
  })

  $("#home-safely").on("click", function(e){
    console.log("I'm home!!")
    e.preventDefault();
    $.ajax({
      url: "http://172.16.50.232:8080/end",
      crossDomain : true,
    })
    .done(function(serverResponse){
      $("#home-safely").hide();
      $("#show-events").show();
      console.log(serverResponse + "This is the server response");

    })
  })

});

$(document).ready(function(){

  // var turbolinks = require('turbolinks')

  $("#walk-me-home").on("click", function(e){
    e.preventDefault();

    $.ajax({
      url: "/sms/text_friend"
    })
    .done(function(serverResponse){

      console.log(serverResponse + " This is the server response");
    })

    .fail(function(serverResponse){

      console.log("Request failed");
    })

    $.ajax({
      url: "http://172.16.50.232:8080/start",
      crossDomain : true,
    })
    .done(function(serverResponse){
      $("#walk-me-home").hide();
      $("#home-safely").show();
      console.log(serverResponse + "This is the server response");
    })
  // need to add failure response
  })

  $("#home-safely").on("click", function(e){
    console.log("I'm home!!")
    e.preventDefault();
    $.ajax({
      url: "http://172.16.50.232:8080/end",
      crossDomain : true,
    })
    .done(function(serverResponse){
      $("#home-safely").hide();
      $("#show-events").show();
      console.log(serverResponse + "This is the server response");

    })
  })

});

Add ajax call to sms controller


PT = PT || {};

PT.downloadCsv = function(serverResponse){
  var survey = serverResponse.survey;
  var responses = serverResponse.responses;
  var a = document.createElement('a');
  var csvString = "";

  //Write title & prompts
  csvString += survey.title + "\n";
  csvString += 'Date of submission,"Location of submission (lat, lon)",';
  survey.inputs.forEach(function(input){
    csvString += '"' + input.label + '",';
  })

  //Write responses
  responses.forEach(function(response){
    csvString += "\n" + response.timestamp + ","
      + '"' + response.locationstamp.lat + ", " + response.locationstamp.lon + '",';

    response.answers.forEach(function(answer){
      if(answer.value){
        if (typeof(answer.value) == "string"){
          csvString += '"' + answer.value + '"';
        } else if(answer.value.constructor == Array) {
          csvString += '"' + answer.value.join(",") + '"';
        } else {
          csvString += '"' + answer.value.lat + ", " + answer.value.lon + '"';
        }
      }
      csvString += ",";
    })
  })

  a.href = "data:application/csv;charset=utf-8," + encodeURIComponent(csvString);
  a.target = "_blank";
  a.download = "PT_Data_" + survey.code + ".csv";
  document.body.appendChild(a);
  a.click();
};

PT = PT || {};

PT.downloadCsv = function(serverResponse){
  var survey = serverResponse.survey;
  var responses = serverResponse.responses;
  var a = document.createElement('a');
  var csvString = "";

  //Write title & prompts
  csvString += survey.title + "\n";
  csvString += 'Date of submission,"Location of submission (lat, lon)",';
  survey.inputs.forEach(function(input){
    csvString += '"' + input.label + '",';
  })

  //Write responses
  responses.forEach(function(response){
    csvString += "\n" + response.timestamp + ","
      + '"' + response.locationstamp.lat + ", " + response.locationstamp.lon + '",';

    response.answers.forEach(function(answer){
      if(answer.value){
        if (typeof(answer.value) == "string"){
          csvString += '"' + answer.value + '"';
        } else if(answer.value.constructor == Array) {
          csvString += '"' + answer.value.join(",") + '"';
        } else {
          csvString += '"' + answer.value.lat + ", " + answer.value.lon + '"';
        }
      }
      csvString += ",";
    })
  })

  a.href = "data:application/csv;charset=utf-8," + "\uFEFF" + encodeURIComponent(csvString);
  a.target = "_blank";
  a.download = "PT_Data_" + survey.code + ".csv";
  document.body.appendChild(a);
  a.click();
};

Add utf-8 BOM to CSV download


/** DO NOT MODIFY **/
import React, { Component } from "react";
import { render } from "react-dom";

import { Root } from "gluestick-shared";
import { match } from "react-router";
import routes from "./routes";
import store from "./.store";
import { StyleRoot } from "radium";

// Make sure that webpack considers new dependencies introduced in the Index
// file
import "../../Index.js";

export default class Entry extends Component {
  static defaultProps = {
    store: store()
  };

  render () {
    const {
      routerContext,
      radiumConfig,
      store
    } = this.props;

    return (
      <StyleRoot radiumConfig={radiumConfig}>
        <Root routerContext={routerContext} routes={routes} store={store} />
      </StyleRoot>
    );
  }
}

Entry.start = function () {
  match({routes, location: window.location.pathname}, (error, redirectLocation, renderProps) => {
    render(<Entry radiumConfig={{userAgent: window.navigator.userAgent}} {...renderProps} />, document.getElementById("main"));
  });
};

/** DO NOT MODIFY **/
import React, { Component } from "react";
import { render } from "react-dom";

// Make sure that webpack considers new dependencies introduced in the Index
// file
import "../../Index.js";

import { Root } from "gluestick-shared";
import { match } from "react-router";
import routes from "./routes";
import store from "./.store";
import { StyleRoot } from "radium";

export default class Entry extends Component {
  static defaultProps = {
    store: store()
  };

  render () {
    const {
      routerContext,
      radiumConfig,
      store
    } = this.props;

    return (
      <StyleRoot radiumConfig={radiumConfig}>
        <Root routerContext={routerContext} routes={routes} store={store} />
      </StyleRoot>
    );
  }
}

Entry.start = function () {
  match({routes, location: window.location.pathname}, (error, redirectLocation, renderProps) => {
    render(<Entry radiumConfig={{userAgent: window.navigator.userAgent}} {...renderProps} />, document.getElementById("main"));
  });
};

Move Index import to the top to fix css order issue


console.log("Helllo world");
var virus = document.querySelector("div");
virus.style.top = "400px";
var x = 1;
var velocity = .1; // px per millisecond
var startTime = Date.now();

timer = setInterval(function() {
	var t = Date.now() - startTime;
	x = velocity * t;
	virus.style.left = x + "px";
	if ( x > screen.width) {
	startTime = Date.now();
	}
},20); // ms  | 1000/20 = 50 frames per second (50 fps)

console.log("Helllo world");
var virus = document.querySelector("div");
virus.style.top = "400px";
var x = 1;
var y = 0;
var vy = 0;
var velocity = .1; // px per millisecond
var startTime = Date.now();
var clickTime;
timer = setInterval(function animate() {
	var t = Date.now() - startTime;
	x = velocity * t;
	virus.style.left = x + "px";
	if ( x > document.body.clientWidth) {
		startTime = Date.now();
	}
	if (vy >= .1) {
		var t = Date.now() - clickTime;
		y = vy * t + 400;
		virus.style.top = y + "px";
	}
},20); // ms  | 1000/20 = 50 frames per second (50 fps)

virus.addEventListener("click", function onclick(event) {
	vy = .1;
	clickTime = Date.now();
});

Add y-dimension, downwards movement, clickHandler


// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
        require('karma-jasmine'),
        require('karma-chrome-launcher'),
        require('karma-jasmine-html-reporter'),
        require('karma-coverage-istanbul-reporter'),
        require('@angular/cli/plugins/karma')
    ],
    client:{
        clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    files: [
      { pattern: './src/test.ts', watched: false }
    ],
    preprocessors: {
      './src/test.ts': ['@angular/cli']
    },
    coverageIstanbulReporter: {
        reports: ['html', 'lcovonly'],
        fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: config.angularCli && config.angularCli.codeCoverage
        ? ['progress', 'coverage-istanbul']
        : ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false
  });
};

// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
        require('karma-jasmine'),
        require('karma-chrome-launcher'),
        require('karma-jasmine-html-reporter'),
        require('karma-coverage-istanbul-reporter'),
        require('@angular/cli/plugins/karma')
    ],
    client:{
        clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    files: [
      { pattern: './src/test.ts', watched: false }
    ],
    preprocessors: {
      './src/test.ts': ['@angular/cli']
    },
    coverageIstanbulReporter: {
        reports: ['html', 'lcovonly'],
        fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: config.angularCli && config.angularCli.codeCoverage
        ? ['progress', 'coverage-istanbul']
        : ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    mime: {
        'text/x-typescript': ['ts','tsx']
    }
  });
};

Fix tests runtime error. Add extension ".ts" MIME type.


Johnson.load(PLUGIN_PREFIX + "/lib/jquery.fn.js");
Johnson.load(PLUGIN_PREFIX + "/lib/jquery.print.js");
Johnson.load(PLUGIN_PREFIX + "/tutorial/tabs.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.builder.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.matchers.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.events.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.behaviors.js");
Johnson.load(PLUGIN_PREFIX + "/lib/smoke.core.js");
Johnson.load(PLUGIN_PREFIX + "/lib/smoke.mock.js");
Johnson.load(PLUGIN_PREFIX + "/lib/smoke.stub.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.mocking.js");
Johnson.load(PLUGIN_PREFIX + "/lib/consoleReportForRake.js");
Johnson.load(PLUGIN_PREFIX + "/tutorial/tabs_spec.js");

jQuery(document).trigger("ready")
jQuery(window).trigger("load");

Johnson.load(PLUGIN_PREFIX + "/lib/jquery.fn.js");
Johnson.load(PLUGIN_PREFIX + "/lib/jquery.print.js");
Johnson.load(PLUGIN_PREFIX + "/tutorial/tabs.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.builder.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.matchers.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.events.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.behaviors.js");
Johnson.load(PLUGIN_PREFIX + "/lib/smoke.core.js");
Johnson.load(PLUGIN_PREFIX + "/lib/smoke.mock.js");
Johnson.load(PLUGIN_PREFIX + "/lib/smoke.stub.js");
Johnson.load(PLUGIN_PREFIX + "/lib/screw.mocking.js");
Johnson.load(PLUGIN_PREFIX + "/lib/consoleReportForRake.js");
Johnson.load(PLUGIN_PREFIX + "/tutorial/tabs_spec.js");

jQuery.ajaxSetup({async: false});
jQuery(document).trigger("ready")
jQuery(window).trigger("load");

Make XHRs synchronous so they can be tested more easily


var _ = require('lodash')
var fs = require('fs')
var gzip = require('gzip-size')
var filesize = require('filesize')
var cssstats = require('cssstats')

var module = require('tachyons-images/package.json')
var moduleCss = fs.readFileSync('node_modules/tachyons-images/tachyons-images.min.css', 'utf8')
var moduleObj = cssstats(moduleCss)
var moduleSize = filesize(moduleObj.gzipSize)

var srcCSS = fs.readFileSync('./src/_images.css', 'utf8')
var navDocs = fs.readFileSync('./templates/nav_docs.html', 'utf8')

var template = fs.readFileSync('./templates/docs/images/index.html', 'utf8')
var tpl = _.template(template)
var html = tpl({
  moduleVersion: module.version,
  moduleSize: moduleSize,
  moduleObj: moduleObj,
  srcCSS: srcCSS,
  navDocs: navDocs
})

fs.writeFileSync('./docs/general/images/index.html', html)

var _ = require('lodash')
var fs = require('fs')
var gzip = require('gzip-size')
var filesize = require('filesize')
var cssstats = require('cssstats')

var module = require('tachyons-images/package.json')
var moduleCss = fs.readFileSync('node_modules/tachyons-images/tachyons-images.min.css', 'utf8')
var moduleObj = cssstats(moduleCss)
var moduleSize = filesize(moduleObj.gzipSize)

var srcCSS = fs.readFileSync('./src/_images.css', 'utf8')
var navDocs = fs.readFileSync('./templates/nav_docs.html', 'utf8')
var siteFooter = fs.readFileSync('./templates/footer.html', 'utf8')

var template = fs.readFileSync('./templates/docs/images/index.html', 'utf8')
var tpl = _.template(template)
var html = tpl({
  moduleVersion: module.version,
  moduleSize: moduleSize,
  moduleObj: moduleObj,
  srcCSS: srcCSS,
  navDocs: navDocs,
  siteFooter: siteFooter
})

fs.writeFileSync('./docs/general/images/index.html', html)

Add site footer to each documentation generator


/* @flow */

import React from 'react'
import {Avatar, Box, Text, Button} from '../common-adapters'
import {globalStyles, globalMargins} from '../styles'
import {noAvatarMessage, hasAvatarMessage} from './edit-avatar.shared'

import type {Props} from './edit-avatar'

const Render = ({keybaseUsername, hasAvatar, onAck}: Props) => {
  const text = !hasAvatar ? noAvatarMessage : hasAvatarMessage

  return (
    <Box style={{...globalStyles.flexBoxColumn, flex: 1}}>
      <Box style={{...globalStyles.flexBoxColumn, alignItems: 'center', padding: globalMargins.large}}>
        <Avatar size={176} username={keybaseUsername} />
        <Text type='Body' style={{marginTop: globalMargins.medium, textAlign: 'center'}}>{text}</Text>
        <Button type='Primary' onClick={onAck} label='Got it!' style={{marginTop: globalMargins.medium}} />
      </Box>
    </Box>
  )
}

export default Render

/* @flow */

import React from 'react'
import {Avatar, Box, Text, Button} from '../common-adapters'
import {globalStyles, globalMargins} from '../styles'
import {noAvatarMessage, hasAvatarMessage} from './edit-avatar.shared'

import type {Props} from './edit-avatar'

const Render = ({keybaseUsername, hasAvatar, onAck}: Props) => {
  const text = !hasAvatar ? noAvatarMessage : hasAvatarMessage

  return (
    <Box style={{...globalStyles.flexBoxColumn, flex: 1, alignItems: 'center', justifyContent: 'center', padding: globalMargins.large}}>
      <Avatar size={176} username={keybaseUsername} />
      <Text type='Body' style={{marginTop: globalMargins.medium, textAlign: 'center'}}>{text}</Text>
      <Button type='Primary' onClick={onAck} label='Got it!' style={{marginTop: globalMargins.medium}} />
    </Box>
  )
}

export default Render

Fix vertical alignment of edit avatar screen


describe("$.set", function() {
	it("exists", function() {
		expect($.set).to.exist;
	});

	it("sets options on the provided subject", function() {
		var element = $.set(document.createElement("nav"), {
			style: {
				color: "red"
			}
		});

		expect(element).to.exist;
		expect(element.style.color).to.equal("red");
	});

	it("can be called on elements", function() {
		var element = document.createElement("nav");
		element._.set({className: "main-navigation"});

		expect(element.className).to.equal("main-navigation");
	});

	it("sets other options as properties or attributes on the subject", function() {
		var element = $.set(document.createElement("input"), {
			id: "the-main-one",
			type: "text",
			disabled: true
		});

		expect(element.id).to.equal("the-main-one");
		expect(element.disabled).to.be.true;
		expect(element.type).to.equal("text");
	});
});

describe("$.set", function() {
	it("exists", function() {
		expect($.set).to.exist;
	});

	it("sets options on the provided subject", function() {
		var element = $.set(document.createElement("nav"), {
			style: {
				color: "red"
			}
		});

		expect(element).to.exist;
		expect(element.style.color).to.equal("red");
	});

	it("can be called on elements", function() {
		var element = document.createElement("nav");
		element._.set({className: "main-navigation"});

		expect(element.className).to.equal("main-navigation");
	});

	xit("can be called on arrays", function() {
		var list = [
			document.createElement("li"),
			document.createElement("li"),
			document.createElement("li")
		];

		list._.set({className: "list-part"});

		list.forEach(function(item) {
			expect(item.className).to.equal("list-part");
		});
	});

	it("sets other options as properties or attributes on the subject", function() {
		var element = $.set(document.createElement("input"), {
			id: "the-main-one",
			type: "text",
			disabled: true
		});

		expect(element.id).to.equal("the-main-one");
		expect(element.disabled).to.be.true;
		expect(element.type).to.equal("text");
	});
});

Add failing test for calling set on arrays


var p;
var drawings = [];

var DrawingManager = function (p5Sketch) {
  p = p5Sketch;
};

DrawingManager.prototype.add = function (pulse) {
  console.log('Added ' + pulse);
  drawings.push(pulse);
}

DrawingManager.prototype.drawAll = function () {
  for (var i = drawings.length - 1; i >= 0; i--) {
    drawings[i].draw(p);
  };
}

module.exports = DrawingManager;

var p;
var drawings = [];

var DrawingManager = function (p5Sketch) {
  p = p5Sketch;
};

DrawingManager.prototype.add = function (drawing) {
  console.log('Added ' + drawing);
  drawings.unshift(drawing);
}

DrawingManager.prototype.drawAll = function () {
  for (var i = drawings.length - 1; i >= 0; i--) {
    drawings[i].draw(p);

    if (drawings[i].done()) {
      drawings.splice(i, 1);
      i--;
    }
  };
}

module.exports = DrawingManager;

Add add garbage collection and fix drawing order in the manager


import Ember from 'ember';

export default Ember.Route.extend({
});

import Ember from 'ember';
import config from '../config/environment';

export default Ember.Route.extend({
  model: function(params) {
      var CLIENT_ID = config.myCLIENT_ID;
      var CLIENT_SECRET = config.myCLIENT_SECRET;
      var location= Object.values(params);
      var url = 'https://api.foursquare.com/v2/venues/search?near='+location+'&client_id='+CLIENT_ID+'&client_secret='+CLIENT_SECRET+'&v=20171003';
    return Ember.$.getJSON(url).then(function(responseJSON) {

      return responseJSON.response.venues;
    });
  },
});

Add a model to access the data from Foursquare API


// Copyright 2015, EMC, Inc.

module.exports = {
    friendlyName: 'Bootstrap Ubuntu',
    injectableName: 'Task.Linux.Bootstrap.Ubuntu',
    implementsTask: 'Task.Base.Linux.Bootstrap',
    options: {
        kernelFile: 'vmlinuz-3.16.0-25-generic',
        initrdFile: 'initrd.img-3.16.0-25-generic',
        kernelUri: '{{ api.server }}/common/{{ options.kernelFile }}',
        initrdUri: '{{ api.server }}/common/{{ options.initrdFile }}',
        basefs: 'common/base.trusty.3.16.0-25-generic.squashfs.img',
        overlayfs: 'common/discovery.overlay.cpio.gz',
        profile: 'linux.ipxe',
        comport: 'ttyS0'
    },
    properties: {
        os: {
            linux: {
                distribution: 'ubuntu',
                release: 'trusty',
                kernel: '3.16.0-25-generic'
            }
        }
    }
};

// Copyright 2015, EMC, Inc.

module.exports = {
    friendlyName: 'Bootstrap Ubuntu',
    injectableName: 'Task.Linux.Bootstrap.Ubuntu',
    implementsTask: 'Task.Base.Linux.Bootstrap',
    options: {
        kernelFile: 'vmlinuz-3.13.0-32-generic',
        initrdFile: 'initrd.img-3.13.0-32-generic',
        kernelUri: '{{ api.server }}/common/{{ options.kernelFile }}',
        initrdUri: '{{ api.server }}/common/{{ options.initrdFile }}',
        basefs: 'common/base.trusty.3.13.0-32-generic.squashfs.img.tiny',
        overlayfs: 'common/discovery.overlay.cpio.gz.tiny',
        profile: 'linux.ipxe',
        comport: 'ttyS0'
    },
    properties: {
        os: {
            linux: {
                distribution: 'ubuntu',
                release: 'trusty',
                kernel: '3.13.0-32-generic'
            }
        }
    }
};

Revert discovery images used to the 3.13.0-32-generic kernel


module.exports = (db, Sequelize) => {
  var User = db.define('users', {
    id: {
      type: Sequelize.INTEGER,
      autoIncrement: true,
      primaryKey: true
    },
    name: Sequelize.STRING,
    email: Sequelize.STRING,
    address: Sequelize.STRING,
    role: Sequelize.STRING,
  });

  return User;
};

module.exports = (db, Sequelize) => {
  var User = db.define('users', {
    id: {
      type: Sequelize.INTEGER,
      autoIncrement: true,
      primaryKey: true
    },
    name: Sequelize.STRING,
    email: Sequelize.STRING,
    address: Sequelize.STRING,
    city: Sequelize.STRING,
    state: Sequelize.STRING,
    zip: Sequelize.STRING,
    country: Sequelize.STRING,
    role: Sequelize.STRING,
  });

  return User;
};

Split User address data into separate properties


import Twitter from 'twitter'
import config from 'config'
import storage from 'electron-json-storage-sync'

const OAUTH_TOKEN_KEY = 'oauthToken'

const oauthInfo = storage.get(OAUTH_TOKEN_KEY)

const client = new Twitter({
  consumer_key: config.get('consumerKey'),
  consumer_secret: config.get('consumerSecret'),
  access_token_key: oauthInfo.data.oauth_access_token,
  access_token_secret: oauthInfo.data.oauth_access_token_secret
})

const params = {
  include_entities: true,
  tweet_mode: 'extended'
}

const state = {
  timeline: []
}

const mutations = {
  FETCH_TIMELINE (state, tweets) {
    state.timeline = tweets
  }
}

const actions = {
  fetchTimeline ({ commit }) {
    // do something async
    fetchTweets('statuses/home_timeline')
      .then((tweets) => {
        commit('FETCH_TIMELINE', tweets)
      })
  }
}

function fetchTweets (endpoint) {
  return new Promise((resolve, reject) => {
    client.get(endpoint, params, (err, tweets, res) => {
      if (!err) {
        resolve(tweets)
      } else {
        reject(err)
      }
    })
  })
}

export default {
  state,
  mutations,
  actions
}

import Twitter from 'twitter'
import config from 'config'
import storage from 'electron-json-storage-sync'

const OAUTH_TOKEN_KEY = 'oauthToken'

const oauthInfo = storage.get(OAUTH_TOKEN_KEY)

const client = new Twitter({
  consumer_key: config.get('consumerKey'),
  consumer_secret: config.get('consumerSecret'),
  access_token_key: oauthInfo.data.oauth_access_token,
  access_token_secret: oauthInfo.data.oauth_access_token_secret
})

const params = {
  include_entities: true,
  tweet_mode: 'extended'
}

const state = {
  timeline: [],
  mentions: []
}

const mutations = {
  FETCH_TIMELINE (state, tweets) {
    state.timeline = tweets
  },
  FETCH_MENTIONS (state, tweets) {
    state.mentions = tweets
  }
}

const actions = {
  fetchTimeline ({ commit }) {
    // do something async
    fetchTweets('statuses/home_timeline')
      .then((tweets) => {
        commit('FETCH_TIMELINE', tweets)
      })
  },
  fetchMentions ({ commit }) {
    // do something async
    fetchTweets('statuses/mentions_timeline')
      .then((tweets) => {
        commit('FETCH_MENTIONS', tweets)
      })
  }
}

function fetchTweets (endpoint) {
  return new Promise((resolve, reject) => {
    client.get(endpoint, params, (err, tweets, res) => {
      if (!err) {
        resolve(tweets)
      } else {
        reject(err)
      }
    })
  })
}

export default {
  state,
  mutations,
  actions
}

Add fetch mention timeline method


import { atob } from 'Base64';
import { PrivateAPI } from '@r/private';

import Session from '../../app/models/Session';
import makeSessionFromData from './makeSessionFromData';
import setSessionCookies from './setSessionCookies';
import * as sessionActions from '../../app/actions/session';

export default async (ctx, dispatch, apiOptions) => {
  // try to create a session from the existing cookie
  // if the session is malformed somehow, the catch will trigger when trying
  // to access it
  const tokenCookie = ctx.cookies.get('token');
  if (!tokenCookie) {
    return;
  }

  const sessionData = JSON.parse(atob(tokenCookie));
  let session = new Session(sessionData);

  // if the session is invalid, try to use the refresh token to grab a new
  // session.
  if (!session.isValid) {
    const data = await PrivateAPI.refreshToken(apiOptions, sessionData.refreshToken);
    session = makeSessionFromData({ ...data, refresh_token: sessionData.refreshToken });

    // don't forget to set the cookies with the new session, or the session
    // will remain invalid the next time the page is fetched
    setSessionCookies(ctx, session);
  }

  // push the session into the store
  dispatch(sessionActions.setSession(session));
};

import { atob } from 'Base64';
import { PrivateAPI } from '@r/private';

import Session from '../../app/models/Session';
import makeSessionFromData from './makeSessionFromData';
import setSessionCookies from './setSessionCookies';
import * as sessionActions from '../../app/actions/session';

export default async (ctx, dispatch, apiOptions) => {
  // try to create a session from the existing cookie
  // if the session is malformed somehow, the catch will trigger when trying
  // to access it
  const tokenCookie = ctx.cookies.get('token');
  const redditSessionExists = ctx.cookies.get('reddit_session');
  if (!(tokenCookie || redditSessionExists)) {
    return;
  }

  let session;
  let sessionData;

  if (tokenCookie) {
    sessionData = JSON.parse(atob(tokenCookie));
    session = new Session(sessionData);
  } else {
    // try to convert reddit session cookie
    const cookies = ctx.headers.cookie.replace(/__cf_mob_redir=1/, '__cf_mob_redir=0').split(';');
    sessionData = await PrivateAPI.convertCookiesToAuthToken(apiOptions, cookies);
    session = new Session(sessionData);
  }

  // if the session is invalid, try to use the refresh token to grab a new
  // session.
  if (!session.isValid) {
    const data = await PrivateAPI.refreshToken(apiOptions, sessionData.refreshToken);
    session = makeSessionFromData({ ...data, refresh_token: sessionData.refreshToken });

    // don't forget to set the cookies with the new session, or the session
    // will remain invalid the next time the page is fetched
    setSessionCookies(ctx, session);
  }

  // push the session into the store
  dispatch(sessionActions.setSession(session));
};

Add logic to convert reddit dot com cookies


/**
 * Created by djarosz on 11/6/15.
 */
/**
 * The purpose of this file is to store all functions and utilities that are used by multiple routes.
 */

function filterBody(strings) {
    return function (req, res, next) {
        var k, found = false;
        for (k in req.body) {
            if (req.body.hasOwnProperty(k)) {
                if (strings.indexOf(k) !== -1) {
                    found = true;
                } else {
                    req.body[k] = null;
                }
            }
        }
        if (found) {
            next();
        } else {
            return res.send(400, 'cannot find required information in body');
        }
    };
}

module.exports = {
    filterBody: filterBody
};

/**
 * Created by djarosz on 11/6/15.
 */
/**
 * The purpose of this file is to store all functions and utilities that are used by multiple routes.
 */

function filterBody(strings) {
    return function (req, res, next) {
        var k, found = false;
        for (k in req.body) {
            if (req.body.hasOwnProperty(k)) {
                if (strings.indexOf(k) !== -1) {
                    found = true;
                } else {
                    req.body[k] = null;
                }
            }
        }
        if (found) {
            next();
        } else {
            return res.send(400, 'cannot find required information in body');
        }
    };
}

function checkUserRole(req, role){
    if(req.session.roles != undefined && req.session.roles.indexOf(role) != -1) {
        return true;
    }
    else {
        return false;
    }
}

module.exports = {
    filterBody: filterBody,
    checkUserRole: checkUserRole
};

Add a utility that checks if a user has a certain role


import React from "react";
import ReactDOM from "react-dom";
import Chart from "react-google-charts";
// Ref : https://developers.google.com/chart/interactive/docs/gallery/histogram

const data = [
  ["Name", "Salary", "Full time employee"],
  ["Mike", { v: 10000, f: "$10,000" }, true],
  ["Jim", { v: 8000, f: "$8,000" }, false],
  ["Alice", { v: 12500, f: "$12,500" }, true],
  ["Bob", { v: 7000, f: "$7,000" }, true]
];
const options = {
  title: "Company Performance",
  curveType: "function",
  legend: { position: "bottom" }
};
class App extends React.Component {
  render() {
    return (
      <div className="App">
        <Chart
          chartType="Table"
          width="100%"
          height="400px"
          data={data}
          options={options}
        />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

import React from "react";
import ReactDOM from "react-dom";
import Chart from "react-google-charts";
// Ref : https://developers.google.com/chart/interactive/docs/gallery/histogram

const data = [
  ["Name", "Salary", "Full time employee"],
  ["Mike", { v: 10000, f: "$10,000" }, true],
  ["Jim", { v: 8000, f: "$8,000" }, false],
  ["Alice", { v: 12500, f: "$12,500" }, true],
  ["Bob", { v: 7000, f: "$7,000" }, true]
];
const options = {
  title: "Company Performance",
  curveType: "function",
  legend: { position: "bottom" },
  pageSize: 1
};
class App extends React.Component {
  render() {
    return (
      <div className="App">
        <Chart
          chartType="Table"
          width="100%"
          height="400px"
          data={data}
          options={options}
        />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Add pagesize to table demo.


angular.module('fleetonrails.controllers.login-controller', [])

    .controller('LoginController', ['$scope', 'LoginService', function ($scope, LoginService) {
        $scope.login = function () {
            LoginService.loginWithPassword($scope.user.email, $scope.user.password)
                .success(function (data, status) {
                    localStorage.setItem("access_token", data.access_token);
                    localStorage.setItem("refresh_token", data.refresh_token);
                    console.log("access_token", localStorage.getItem("access_token"));
                    console.log("refresh_token", localStorage.getItem("refresh_token"));
                }).error(function (data, status) {
                    console.log('fail', data, status)
                });;
        }
    }]);

angular.module('fleetonrails.controllers.login-controller', [])

    .controller('LoginController', ['$scope', 'LoginService', function ($scope, LoginService) {
        $scope.login = function () {
            LoginService.loginWithPassword($scope.user.email, $scope.user.password)
                .success(function (data, status) {
                    localStorage.setItem("access_token", data.access_token);
                    localStorage.setItem("refresh_token", data.refresh_token);
                    console.log("access_token", localStorage.getItem("access_token"));
                    console.log("refresh_token", localStorage.getItem("refresh_token"));
                }).error(function (data, status) {
                    console.log('fail', data, status)
                });
        }
    }]);

Add refresh token service method


var $ = document.getElementById.bind(document);
var exampleTests = require('./example-tests');
var Main = require('../src/main/main-controller');

var providedByAceEditor = function() {/* noop() */};
var isMac = navigator.platform.indexOf('Mac') === 0;
var metaKey = isMac ? 'Meta' : 'Control';
var shortcuts = [
  [[metaKey, 'S'], executeTestCode, 'Save+Run'],
  [[metaKey, 'D'], providedByAceEditor(), 'Delete line'],
  [[metaKey, 'Shift', 'D'], providedByAceEditor(), 'Duplicate line'],
  [[metaKey, '/'], providedByAceEditor(), 'Comment in/out line'],

  [[metaKey, 'I', 'E'], providedByAceEditor(), '???'],
  [[metaKey, 'I', 'I'], providedByAceEditor(), '???'],
  [[metaKey, 'I', 'E', 'E'], providedByAceEditor(), '???'],

  [['Shift', 'F6'], refactoringRename, 'Rename (refactoring)']
];

var main = new Main($('tddbin'), {
  initialContent: exampleTests.simplePassingTestCode,
  iframeSrcUrl: '../src/test-runner/mocha/spec-runner.html',
  shortcuts: shortcuts
});

function executeTestCode() {
  main.runEditorContent();
}
function refactoringRename() {
  main.placeCursorsForRenaming();
}

var $ = document.getElementById.bind(document);
var exampleTests = require('./example-tests');
var Main = require('../src/main/main-controller');
var Shortcut = require('../src/keyboard-shortcut/shortcut');

var providedByAceEditor = function() {/* noop() */};
var isMac = navigator.platform.indexOf('Mac') === 0;
var metaKey = isMac ? 'Meta' : 'Control';
var shortcuts = [
  new Shortcut([metaKey, 'S'], executeTestCode, 'Save+Run'),
  new Shortcut([metaKey, 'D'], providedByAceEditor(), 'Delete line'),
  new Shortcut([metaKey, 'Shift', 'D'], providedByAceEditor(), 'Duplicate line'),
  new Shortcut([metaKey, '/'], providedByAceEditor(), 'Comment in/out line'),

  new Shortcut([metaKey, 'I', 'E'], providedByAceEditor(), '???'),
  new Shortcut([metaKey, 'I', 'I'], providedByAceEditor(), '???'),
  new Shortcut([metaKey, 'I', 'E', 'E'], providedByAceEditor(), '???'),

  new Shortcut(['Shift', 'F6'], refactoringRename, 'Rename (refactoring)')
];

var main = new Main($('tddbin'), {
  initialContent: exampleTests.simplePassingTestCode,
  iframeSrcUrl: '../src/test-runner/mocha/spec-runner.html',
  shortcuts: shortcuts
});

function executeTestCode() {
  main.runEditorContent();
}
function refactoringRename() {
  main.placeCursorsForRenaming();
}

Create shortcut instances for each one.


export function capitalizeFirstLetter (string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

export function shortenNumber (number, decimals, abbreviate) {
  decimals = (decimals === undefined) ? 0 : decimals
  abbreviate = (abbreviate === undefined) ? true : abbreviate
  let k = 'K'
  let m = 'M'
  let b = 'B'
  if (!abbreviate) {
    k = 'Thousand'
    m = 'Million'
    b = 'Billion'
  }
  if (number >= 1000000000) {
    return `${Number((number / 1000000000).toFixed(decimals))} ${b}`
  } else if (number >= 1000000) {
    return `${Number((number / 1000000).toFixed(decimals))} ${m}`
  } else if (number >= 1000) {
    return `${Number((number / 1000).toFixed(decimals))} ${k}`
  } else {
    return number
  }
}

export function capitalizeFirstLetter (string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

export function shortenNumber (number, decimals, abbreviate) {
  decimals = (decimals === undefined) ? 0 : decimals
  abbreviate = (abbreviate === undefined) ? true : abbreviate
  let k = 'K'
  let m = 'M'
  let b = 'B'
  if (!abbreviate) {
    k = 'Thousand'
    m = 'Million'
    b = 'Billion'
  }
  if (Math.abs(number) >= 1000000000) {
    return `${Number((number / 1000000000).toFixed(decimals))} ${b}`
  } else if (Math.abs(number) >= 1000000) {
    return `${Number((number / 1000000).toFixed(decimals))} ${m}`
  } else if (Math.abs(number) >= 1000) {
    return `${Number((number / 1000).toFixed(decimals))} ${k}`
  } else {
    return number
  }
}

Set function to work with negative numbers as well


'use strict';

angular.module('geboRegistrantHaiApp')
  .controller('AccountCtrl', function ($scope, Token) {

    $scope.friends = [];

    /**
     * init
     */
    $scope.init = function() {
        Token.request({
                action: 'ls',
                resource: 'friends',
                fields: ['name', '_id', 'email'],
          }).
        then(function(friends) {
            $scope.friends = friends;
          }).
        catch(function(err) {
          });
      };
  });

'use strict';

angular.module('geboRegistrantHaiApp')
  .controller('AccountCtrl', function ($scope, Token) {

    $scope.friends = [];

    $scope.agent = Token.data();

    /**
     * init
     */
    $scope.init = function() {
        console.log('AccountCtrl init');
        Token.request({
                action: 'ls',
                resource: 'friends',
                recipient: $scope.agent.email,
                fields: ['name', '_id', 'email'],
          }).
        then(function(friends) {
            $scope.friends = friends;
          }).
        catch(function(err) {
          });
      };
  });

Add recipient param to ls and agent to scope


module.exports = {
  app_host_port: 'streetmix-staging.herokuapp.com',
  header_host_port: 'streetmix-staging.herokuapp.com',
  restapi: {
    baseuri: '/api'
  },
  facebook_app_id: '175861739245183',
  l10n: {
    use_local: false
  }
}

module.exports = {
  app_host_port: 'streetmix-staging.herokuapp.com',
  header_host_port: 'streetmix-staging.herokuapp.com',
  restapi: {
    baseuri: '/api',
    protocol: 'https://'
  },
  facebook_app_id: '175861739245183',
  l10n: {
    use_local: false
  }
}

Fix bug from redirectUrl sent to auth0


// @flow

import React, { Component } from 'react';
import withRedux from 'next-redux-wrapper';
import Error from 'next/error';
import { createStore } from '../store';
import { loadGame } from '../actions';
import { addCurUserToState, getGame } from '../utils/api';
import { SocketProvider } from '../utils/socket/Provider';
import Layout from '../components/Layout';
import GameContainer from '../components/GameContainer';
import FlatrisGame from '../components/FlatrisGame';

type Props = {
  gameExists: boolean
};

class JoinPage extends Component<Props> {
  static async getInitialProps({ req, query, store }) {
    if (req) {
      await addCurUserToState(req, store);
    }

    try {
      const game = await getGame(query.g);
      store.dispatch(loadGame(game));

      return {
        gameExists: true
      };
    } catch (err) {
      return { gameExists: false };
    }
  }

  render() {
    const { gameExists } = this.props;
    if (!gameExists) {
      // TODO: Identify and signal 500s differently
      return <Error statusCode={404} />;
    }

    return (
      <Layout>
        <SocketProvider>
          <GameContainer>
            <FlatrisGame />
          </GameContainer>
        </SocketProvider>
      </Layout>
    );
  }
}

export default withRedux(createStore)(JoinPage);

// @flow

import React, { Component } from 'react';
import withRedux from 'next-redux-wrapper';
import Error from 'next/error';
import { createStore } from '../store';
import { loadGame } from '../actions';
import { addCurUserToState, getGame } from '../utils/api';
import { SocketProvider } from '../utils/socket/Provider';
import Layout from '../components/Layout';
import GameContainer from '../components/GameContainer';
import FlatrisGame from '../components/FlatrisGame';

type Props = {
  statusCode: false | number
};

class JoinPage extends Component<Props> {
  static async getInitialProps({ req, res, query, store }) {
    if (req) {
      await addCurUserToState(req, store);
    }

    try {
      const game = await getGame(query.g);
      store.dispatch(loadGame(game));

      return {
        statusCode: false
      };
    } catch (err) {
      // TODO: Identify and signal 500s differently
      const statusCode = 404;

      // Server side rendered pages will return this status code, whereas
      // client side rendered pages will just render the appropriate message
      if (res) {
        res.statusCode = statusCode;
      }

      return { statusCode };
    }
  }

  render() {
    const { statusCode } = this.props;
    if (statusCode) {
      return <Error statusCode={404} />;
    }

    return (
      <Layout>
        <SocketProvider>
          <GameContainer>
            <FlatrisGame />
          </GameContainer>
        </SocketProvider>
      </Layout>
    );
  }
}

export default withRedux(createStore)(JoinPage);

Include status code to 404 pages


// ==UserScript==
// @name Flight Management Computer for GeoFS
// @description This extension adds an FMC which controls features such as VNAV, LNAV, route, progress information, etc.
// @namespace GeoFS-Plugins
// @match http://*/geofs.php*
// @run-at document-end
// @version 0.5.1-beta
// @grant none
// ==/UserScript==

// ==UserScript==
// @name Flight Management Computer for GeoFS
// @description This extension adds an FMC which controls features such as VNAV, LNAV, route, progress information, etc.
// @author Harry Xue
// @namespace GeoFS-Plugins
// @match http://*/geofs.php*
// @run-at document-end
// @version 0.5.2
// @grant none
// ==/UserScript==

Update to v0.5.2 for release


/**
 * The default irc-framework interface for nodejs
 * Usage: var IrcFramework = require('irc-framework');
 */

module.exports.Client = require('./build/client');
module.exports.Client.setDefaultTransport(require('./build/transports/net'));

module.exports.ircLineParser = require('./build/irclineparser');

/**
 * The default irc-framework interface for nodejs
 * Usage: var IrcFramework = require('irc-framework');
 */

module.exports.Client = require('./src/client');
module.exports.Client.setDefaultTransport(require('./src/transports/net'));

module.exports.ircLineParser = require('./src/irclineparser');

Use /src/ unless running in the browser for easier debugging


"use strict";

var fs = require('fs');

exports.deleteFileSync = function(filePath, timeInterval) {
    function iterator(filePath, dirs) {
        var stat = fs.stat(filePath);
        if(stat.isDirectory()) {
            dirs.unshift(filePath);//collection dirs
            inner(filePath, dirs);
        } else if(stat.isFile()){
            fs.unlinkSync(filePath);//delete file
        }
    }

    function inner(path, dirs){
        var arr = fs.readdirSync(path);
        for(var i = 0, el ; el = arr[i++];){
            iterator(path+"/"+el,dirs);
        }
    }
    return setInterval(function(path, cb){
        cb = cb || function(){};
        var dirs = [];

        try{
            iterator(path, dirs);
            for(var i = 0, el ; el = dirs[i++];){
                fs.rmdirSync(el);//delete all collection dirs
            }
            cb()
        }catch(e){
            e.code === "ENOENT" ? cb() : cb(e);
        }
    }, timeInterval*1000);
};

"use strict";

var fs = require('fs');

exports.deleteFileSync = function(filePath, timeInterval, callback) {
    function iterator(filePath, dirs, callback) {
        fs.stat(filePath, function(err, stats){
            if(err){
                if (err.message === 'No such file or directory') {
                    // Ignore file not found errors and return an empty result
                    callback(null, "");
                } else {
                    // Pass other errors through as is
                    callback(err);
                }
            } else{
                if(stats.isDirectory()) {
                    dirs.unshift(filePath);//collection dirs
                    inner(filePath, dirs);
                } else if(stats.isFile()){
                    fs.unlinkSync(filePath);//delete file
                }
            }
        })
    }

    function inner(path, dirs){
        var arr = fs.readdirSync(path);
        for(var i = 0, el ; el = arr[i++];){
            iterator(path+"/"+el,dirs);
        }
    }

    var ex = function(path, cb){
        cb = cb || function(){};
        var dirs = [];

        try{
            iterator(path, dirs, function(err, data){
                if(err) cb(err);
                for(var i = 0, el ; el = dirs[i++];){
                    fs.rmdirSync(el);//delete all collection dirs
                }
                cb(data);
            });

        }catch(e){
            e.code === "ENOENT" ? cb() : cb(e);
        }
    };
    return setInterval(ex(filePath, callback), timeInterval*1000);
};

Modify Async && Sync Delete


#!/usr/bin/env node

/**
 * Module dependencies.
 */
var Hapi = require('hapi'),
    handlers = require('./handlers');

var server = Hapi.createServer(8000);

server.route([
  {
    method: 'GET',
    path: '/search/{prefix}',
    handler: handlers.search
  },
  {
    method: 'POST',
    path: '/dictionary',
    handler: handlers.dictionary
  },
]);

if (require.main === module) {
  server.start();
}

module.exports = server;

#!/usr/bin/env node

/**
 * Module dependencies.
 */
var Hapi = require('hapi'),
    handlers = require('./handlers');

var server = Hapi.createServer(8000, {
  payload: {
    maxBytes: process.env.MAX_PAYLOAD_SIZE || 5242880
  }
});

server.route([
  {
    method: 'GET',
    path: '/search/{prefix}',
    handler: handlers.search
  },
  {
    method: 'POST',
    path: '/dictionary',
    handler: handlers.dictionary
  },
]);

if (require.main === module) {
  server.start();
}

module.exports = server;

Set default max payload size to 5 MiB


var debug = require('debug')('vmplate');
var vm = require('vm');

module.exports = function vmplate(string, filename) {

  var script = vm.createScript(compile(string), filename || 'template.vm');

  return function render(locals) {
    return script.runInNewContext(locals);
  };

  function compile(string) {
    var regex = /<%=(.+?)%>/;
    var match;
    var code = 'var str = ""\n';

    function push(str) {
      code += 'str += ' + str + '\n';
    }

    while (match = regex.exec(string)) {
      debug('match', match);

      var pre = string.slice(0, match.index);

      if (pre.length) {
        push(quote(pre));
      }

      push(trim(match[1]));

      string = string.slice(match.index + match[0].length);
    }

    if (string.length) {
      push(quote(string));
    }

    debug('compiled\n' + code);

    return code;
  }

  function quote(str) {
    return JSON.stringify(str);
  }

  function trim(str) {
    return str.trim();
  }

};

var debug = require('debug')('vmplate');
var vm = require('vm');

module.exports = function vmplate(string, filename) {

  var script = vm.createScript(compile(string), filename || 'template.vm');

  return function render(locals) {
    return script.runInNewContext(locals);
  };

  function compile(string) {
    var token = '<%=';
    var index = 0;
    var start = 0;
    var match;
    var script = 'var str = ""\n';

    function push(str) {
      script += 'str += ' + str + '\n';
    }

    function code(str) {
      debug('code %j', str);
      push(trim(str));
    }

    function text(str) {
      debug('text %j', str);
      push(quote(str));
    }

    while ((index = string.indexOf(token, start)) > -1) {
      debug('token=%j start=%s index=%d', token, start, index);

      match = string.slice(start, index);
      start = index + token.length

      switch (token) {
      case '<%=':
        text(match);
        token = '%>';
        break;
      case '%>':
        code(match);
        token = '<%=';
        break;
      }
    }

    if (start < string.length) {
      text(string.slice(start));
    }

    debug('compiled\n' + script);

    return script;
  }

  function quote(str) {
    return JSON.stringify(str);
  }

  function trim(str) {
    return str.trim();
  }

};

Use string scanning instead of regex


/* jshint node: true */
'use strict';

const anybar = require('anybar');
const captureExit = require('capture-exit');
const exec = require('child_process').exec;

captureExit.captureExit();

// Open AnyBar (OSX only)
exec('open --hide --background -a AnyBar', (error, stdout, stderror) => {
  if (error) console.error('exec error: ${error}');
});

// Pulse
let color = 'black';

let pulser;
function pulse() {
  clearInterval(pulser);
  pulser = setInterval(() => {
    anybar(color);
    color = color === 'black' ? 'white' : 'black';
  }, 200);
};

// Back to white on exit
captureExit.onExit(function() {
  clearInterval(pulser);
  return anybar('white');
});

module.exports = {
  name: 'ember-cli-anybar',

  preBuild() {
    pulse();
  },

  buildError: function() {
    clearInterval(pulser);
    anybar('red');
  },

  postBuild: function() {
    clearInterval(pulser);
    anybar('green');
  },

};

/* jshint node: true */
'use strict';

const anybar = require('anybar');
const captureExit = require('capture-exit');
const exec = require('child_process').exec;

captureExit.captureExit();

// Open AnyBar (OSX only)
exec('open --hide --background -a AnyBar', (error, stdout, stderror) => {
  if (error) console.error(`exec error: ${error}`);
});

// Pulse
let color = 'black';

let pulser;
function pulse() {
  clearInterval(pulser);
  pulser = setInterval(() => {
    anybar(color);
    color = color === 'black' ? 'white' : 'black';
  }, 200);
};

// Back to white on exit
captureExit.onExit(function() {
  clearInterval(pulser);
  return anybar('white');
});

module.exports = {
  name: 'ember-cli-anybar',

  preBuild() {
    pulse();
  },

  buildError: function() {
    clearInterval(pulser);
    anybar('red');
  },

  postBuild: function() {
    clearInterval(pulser);
    anybar('green');
  },

};

Use a template literal to expand error messages


/**
 * This basic example shows how to fetch updates to a deal.
 *
 * It starts by fetching the first deal from the account and then fetches 10 latest updates of this deal.
 *
 * Usage:
 * node deals-updates.js YOUR_API_TOKEN
 */

if (!process.argv[2]) {
	process.stderr.write('Please provide the API token!' + "\n");
	process.exit();
}

const pipedrive = require('../lib');

pipedrive.Configuration.apiToken = process.argv[2];

(async () => {
	try {
		const deals = await pipedrive.DealsController.getAllDeals({ start: 0, limit: 1 });

		if (deals.data && deals.data.length > 0) {
			const deal = deals.data[0];

			console.log(`Deal ${deal.title} (${deal.value} ${deal.currency})`);

			const updates = await pipedrive.DealsController.listUpdatesAboutADeal({
				id: deal.id,
				start: 0,
				limit: 10
			});

			for (const update of updates.data) {
				console.log(`${update.object} from ${update.timestamp.split(' ')[0]}:`);
				console.log(JSON.stringify(update.data));
			}
		} else {
			console.log('No deals found on your account.');
		}
	} catch (error) {
		console.log(error);
	}
})();

/**
 * This basic example shows how to fetch updates to a deal.
 *
 * It starts by fetching the first deal from the account and then fetches 10 latest updates of this deal.
 *
 * Usage:
 * node deals-updates.js YOUR_API_TOKEN
 */

if (!process.argv[2]) {
	process.stderr.write('Please provide the API token!' + "\n");
	process.exit();
}

const pipedrive = require('../lib');

pipedrive.Configuration.apiToken = process.argv[2];

(async () => {
	try {
		const deals = await pipedrive.DealsController.getAllDeals({ start: 0, limit: 1 });

		if (deals.data && deals.data.length > 0) {
			const deal = deals.data[0];

			console.log(`Deal ${deal.title} (${deal.value} ${deal.currency})`);

			const updates = await pipedrive.DealsController.listUpdatesAboutADeal({
				id: deal.id,
				start: 0,
				limit: 10
			});

			for (const update of updates.data) {
				console.log(`${update.object} from ${update.timestamp.split(' ')[0]}:`);
				console.log(JSON.stringify(update.data, null, 2));
			}
		} else {
			console.log('No deals found on your account.');
		}
	} catch (error) {
		console.log(error);
	}
})();

Add indentation to JSON in example


import { getOptions, stringifyRequest } from 'loader-utils'

module.exports = function (content, sourceMap) {
  this.cacheable()

  const options = getOptions(this)
  const { buildId, modules } = options

  this.callback(null, `
  // Webpack Polyfill Injector
function main() {${modules.map(module => `\n    require(${stringifyRequest(this, module)});`).join('') + '\n'}}
if (require(${stringifyRequest(this, options.test)})) {
    var js = document.createElement('script');
    js.src = __NEXT_DATA__.publicPath + '${buildId}/polyfill.js';
    js.onload = main;
    js.onerror = function onError(message) {
        console.error('Could not load the polyfills: ' + message);
    };
    document.head.appendChild(js);
} else {
    main();
}
  `, sourceMap)
}

import { getOptions, stringifyRequest } from 'loader-utils'

module.exports = function (content, sourceMap) {
  this.cacheable()

  const options = getOptions(this)
  const { buildId, modules } = options

  this.callback(null, `
  // Webpack Polyfill Injector
function main() {${modules.map(module => `\n    require(${stringifyRequest(this, module)});`).join('') + '\n'}}
if (require(${stringifyRequest(this, options.test)})) {
    window.afterPoly = main;
    var js = document.createElement('script');
    js.onerror = function onError(message) {
      Raven.captureException(new Error('Could not load the polyfills: ' + message));
    };
    js.src = __NEXT_DATA__.publicPath + '${buildId}/polyfill.js';
    document.head.appendChild(js);
} else {
    main();
}
  `, sourceMap)
}

Use callback for polyfill loading


var offgrid = require('./build/Debug/offgrid');

offgrid.init(575);

// Selectively re-export and/or wrap offgrid methods.
exports.blank = offgrid.blank;
exports.red = offgrid.red;
exports.green = offgrid.green;
exports.blue = offgrid.blue;
exports.write = offgrid.write;
exports.send = offgrid.send;

Object.defineProperty(exports, "count", {
  enumerable: true,
  get() {
    return offgrid.count();
  }
});

var offgrid = require('./build/Debug/offgrid');

offgrid.init(350);

// Selectively re-export and/or wrap offgrid methods.
exports.blank = offgrid.blank;
exports.red = offgrid.red;
exports.green = offgrid.green;
exports.blue = offgrid.blue;
exports.write = offgrid.write;
exports.send = offgrid.send;

Object.defineProperty(exports, "count", {
  enumerable: true,
  get() {
    return offgrid.count();
  }
});

Reduce LED count to 350.


module.exports = concatStreams;

function concatStreams(readables, writable) {
  var fn = function asyncRead(s) {
    return new Promise(function(res, rej) {
      var chunks = '';

      s.on('data', chunk => chunks += chunk);

      s.on('end', () => res(chunks));
    });
  };

  var promises = readables.map(fn);

  var results = Promise.all(promises);

  results.then(chunks => {
    var data = chunks.join('\n');

    writable.write(data);
  });
}

module.exports = concatStreams;

function concatStreams(readables, writable) {
  var promises = readables.map(asyncRead);
  var results = Promise.all(promises);

  results.then(buffers => {
    var data = Buffer.concat(buffers);

    writable.write(data);
  });
}

function asyncRead(stream) {
  return new Promise(resolve => {
    var buffers = [];

    stream.on('data', chunk => buffers.push(chunk));
    stream.on('end', () => resolve(Buffer.concat(buffers)));
  });
}

Update `concatStreams` to use `Buffer.concat`


function something()
{
  var x = window.localStorage.getItem('bbb');
  x = x * 1 + 1;
  window.localStorage.setItem('bbb', x);

  alert(x);
}

function add_to_cart(id)
{
  var key = 'product_' + id;
  var x = window.localStorage.getItem(key);
  x = x * 1 + 1;
  window.localStorage.setItem(key, x);

  update_orders_input();
  update_orders_button();
}

function update_orders_input()
{
  var orders = cart_get_orders();
  $('#orders_input').val(orders);
}

function update_orders_button()
{
  var text = 'Cart ('+ list_all_Items() +')';
  $('#orders_button').val(text);
}

function list_all_Items()
{
  total = 0;
  $.each(localStorage, function(key, value){
    total += value * 1;
  });
  return total;
}

function cart_get_orders()
{
  var orders = '';
  for(var i = 0; i < window.localStorage.length; i++)
  {
    var key = window.localStorage.key(i); // get key
    var value = window.localStorage.getItem(key); // get value by key from hash
    if(key.indexOf('product_') == 0)
    {
      orders = orders + key + '=' + value + ',';
    }
  }
  return orders;
}

function cancel_order()
{
  alert('aaa');
  return false;
}

function something()
{
  var x = window.localStorage.getItem('bbb');
  x = x * 1 + 1;
  window.localStorage.setItem('bbb', x);

  alert(x);
}

function add_to_cart(id)
{
  var key = 'product_' + id;
  var x = window.localStorage.getItem(key);
  x = x * 1 + 1;
  window.localStorage.setItem(key, x);

  update_orders_input();
  update_orders_button();
}

function update_orders_input()
{
  var orders = cart_get_orders();
  $('#orders_input').val(orders);
}

function update_orders_button()
{
  var text = 'Cart ('+ list_all_Items() +')';
  $('#orders_button').val(text);
}

function list_all_Items()
{
  total = 0;
  $.each(localStorage, function(key, value){
    total += value * 1;
  });
  return total;
}

function cart_get_orders()
{
  var orders = '';
  for(var i = 0; i < window.localStorage.length; i++)
  {
    var key = window.localStorage.key(i); // get key
    var value = window.localStorage.getItem(key); // get value by key from hash
    if(key.indexOf('product_') == 0)
    {
      orders = orders + key + '=' + value + ',';
    }
  }
  return orders;
}

function cancel_order()
{
  window.localStorage.clear();
  update_orders_input();
  update_orders_button();
  return false;
}

Clear local Storage on cancel


const core = require("sdk/view/core");
const hotkeys = require("sdk/hotkeys");
const tabs = require("sdk/tabs");
const windows = require("sdk/windows").browserWindows;

const helpers = require("./lib/helpers");
const state = require("./lib/state");

function registerListeners(window) {
    let lowLevelWindow = core.viewFor(window);
    lowLevelWindow.addEventListener("click", helpers.maybeDisableIfNewTabButtonClick, true);

    lowLevelWindow.addEventListener("SSWindowStateBusy", function() { state.disableUntilEnabled(); });

    lowLevelWindow.addEventListener("SSWindowStateReady", function() { state.enable(); });
}

exports.main = function(options) {
    console.log("Starting up with reason ", options.loadReason);

    hotkeys.Hotkey({
        combo: "accel-alt-t",
        onPress: helpers.openNewTabAtDefaultPosition,
    });

    tabs.on("open", helpers.maybeMoveTab);

    for (let window of windows) {
        registerListeners(window);
    }

    windows.on("open", registerListeners);
};

exports.onUnload = function(reason) {
    console.log("Closing down with reason ", reason);

};

Add empty onUnload to pass test


'use strict';

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

/*
 * function readSsl (options, callback)
 * Reads the SSL certificate information in the
 * specified options:
 *
 * options.root
 * options.cert
 * options.key
 * options.ca
 */
module.exports = function (options, callback) {
  var read = {};

  function readCertFile(key, file, next) {
    fs.readFile(file, function (err, data) {
      if (err) {
        return next(err);
      } else if (read[key]) {
        if (!Array.isArray(read[key])) {
          read[key] = [read[key]];
        }

        read[key].push(data);
        return next();
      }

      read[key] = data;
      next();
    });
  }

  var sources = ['cert', 'key', 'ca']
    .reduce(function (acc, key) {
      var list = !Array.isArray(options[key])
        ? [options[key]]
        : options[key];

      acc.push.apply(acc, list.map(function (file) {
        return { key: key, file: path.join(options.root, file) };
      }));

      return acc;
    }, []);

  (function readUntilEmpty(err) {
    if (err) {
      return callback(err);
    } else if (!sources.length) {
      return callback(null, read);
    }

    var source = sources.shift();
    readCertFile(source.key, source.file, readUntilEmpty);
  })();
};

'use strict';

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

/*
 * function readSsl (options, callback)
 * Reads the SSL certificate information in the
 * specified options:
 *
 * options.root
 * options.cert
 * options.key
 * options.ca
 */
module.exports = function (options, callback) {
  var read = {};

  function readCertFile(key, file, next) {
    fs.readFile(file, function (err, data) {
      if (err) {
        return next(err);
      } else if (read[key]) {
        if (!Array.isArray(read[key])) {
          read[key] = [read[key]];
        }

        read[key].push(data);
        return next();
      }

      read[key] = data;
      next();
    });
  }

  var sources = ['cert', 'key', 'ca']
    .reduce(function (acc, key) {
      if (!options[key]) { return acc; }

      var list = !Array.isArray(options[key])
        ? [options[key]]
        : options[key];

      acc.push.apply(acc, list.map(function (file) {
        return { key: key, file: path.join(options.root, file) };
      }));

      return acc;
    }, []);

  (function readUntilEmpty(err) {
    if (err) {
      return callback(err);
    } else if (!sources.length) {
      return callback(null, read);
    }

    var source = sources.shift();
    readCertFile(source.key, source.file, readUntilEmpty);
  })();
};

Add fix for "no ca" case.


'use strict';

const choo = require('choo');
const html = require('choo/html');
const app = choo();

app.model({
  state: {
    todos: [],
  },
  reducers: {
    addTodo: (state, data) => {
      const newTodos = state.todos.slice();
      newTodos.push(data);
      return {
        todos: newTodos,
      };
  },
  },
});

const hTodoLi = (todo) => html`<li>${todo.title}</li>`;

const view = (state, prevState, send) => {
  return html`

ChooDo

      <form onsubmit=${(e) => {
        const userInput = e.target.children[0]
        send('addTodo', { title: userInput.value })
        userInput.value = ''
        e.preventDefault()
        }}>

        <input type="text" placeholder="Write your next task here..." id="title" autofocus>
      </form>

        ${state.todos.map(hTodoLi)}

`;
}

app.router([
  ['/', view],
]);

const tree = app.start();
document.body.appendChild(tree);

'use strict';

const choo = require('choo');
const html = require('choo/html');
const app = choo();

app.model({
  state: {
    todos: [],
  },
  reducers: {
    addTodo: (state, data) => {
      const newTodos = state.todos.slice();
      newTodos.push(data);
      return {
        todos: newTodos,
      };
  },
  },
});

const hTodoLi = (todo) => html`<li>${todo.title}</li>`;

const view = (state, prevState, send) => {
  const onTaskSubmition = (e) => {
    const userInput = e.target.children[0];
    send('addTodo', { title: userInput.value });
    userInput.value = '';
    e.preventDefault();
  };

  return html`

ChooDo

      <form onsubmit=${onTaskSubmition}>

        <input type="text" placeholder="Write your next task here..." id="title" autofocus>
      </form>

        ${state.todos.map(hTodoLi)}

`;
}

app.router([
  ['/', view],
]);

const tree = app.start();
document.body.appendChild(tree);

Refactor to take out form logic into its own function


var util = require('util');

var mochaFormatter = {
  suite: "describe('%s', function () {",
  test:  "it('%s');",
  end:   '});'
};

function format(line, type) {
  return util.format(mochaFormatter[type], line.trim());
}

function getIndentLength(line) {
  return (line.match(/ {2}/g) || []).length;
}

module.exports = function (input) {
  var newline = '\n';
  var inputLines = input.split(newline);
  var outputLines = [];

  inputLines.forEach(function (line, index) {
    var indentLength = getIndentLength(line);
    var nextLine = inputLines[index + 1];
    var nextIndentLength = nextLine === undefined ? 0 : getIndentLength(nextLine);

    if (line.length === 0) {
      outputLines.push('');
    } else if (nextLine === undefined || indentLength >= nextIndentLength) {
      outputLines.push(format(line, 'test'));
      if (indentLength > nextIndentLength) {
        for (var i = 0; i < indentLength - nextIndentLength; i++) {
          outputLines.push(mochaFormatter.end);
        }
      }
    } else {
      outputLines.push(format(line, 'suite'));
    }
  });

  return outputLines.join(newline);
};

var util = require('util');

var mochaFormatter = {
  suite: "describe('%s', function () {",
  test:  "it('%s');",
  end:   '});'
};

function format(line, type) {
  if (type === 'end') {
    return mochaFormatter.end;
  } else {
    return util.format(mochaFormatter[type], line.trim());
  }
}

function getIndentLength(line) {
  return (line.match(/ {2}/g) || []).length;
}

module.exports = function (input) {
  var newline = '\n';
  var inputLines = input.split(newline);
  var outputLines = [];

  inputLines.forEach(function (line, index) {
    var indentLength = getIndentLength(line);
    var nextLine = inputLines[index + 1];
    var nextIndentLength = nextLine === undefined ? 0 : getIndentLength(nextLine);

    if (line.length === 0) {
      outputLines.push('');
    } else if (nextLine === undefined || indentLength >= nextIndentLength) {
      outputLines.push(format(line, 'test'));
      if (indentLength > nextIndentLength) {
        for (var i = 0; i < indentLength - nextIndentLength; i++) {
          outputLines.push(format(line, 'end'));
        }
      }
    } else {
      outputLines.push(format(line, 'suite'));
    }
  });

  return outputLines.join(newline);
};

Revert "Remove the 'end' type from format()"


'use strict';

var childProcess = require('child_process');
var nodeBin = process.argv[0];

module.exports = sleep;
function sleep(milliseconds) {
  var start = Date.now();
  if (milliseconds !== Math.floor(milliseconds)) {
    throw new TypeError('sleep only accepts an integer number of milliseconds');
  } else if (milliseconds < 0) {
    throw new RangeError('sleep only accepts a positive number of milliseconds');
  } else if (milliseconds !== (milliseconds | 0)) {
    throw new RangeError('sleep duration out of range')
  }
  milliseconds = milliseconds | 0;

  var shouldEnd = start + milliseconds;
  childProcess.execFileSync(nodeBin, [ '-e',
    'setTimeout(function() {}, ' + shouldEnd + ' - Date.now());'
  ]);
  var end = Date.now();
  return end - start;
}

'use strict';

var childProcess = require('child_process');
var nodeBin = process.argv[0];

module.exports = sleep;
function sleep(milliseconds) {
  var start = Date.now();
  if (milliseconds !== Math.floor(milliseconds)) {
    throw new TypeError('sleep only accepts an integer number of milliseconds');
  } else if (milliseconds < 0) {
    throw new RangeError('sleep only accepts a positive number of milliseconds');
  } else if (milliseconds !== (milliseconds | 0)) {
    throw new RangeError('sleep duration out of range')
  }
  milliseconds = milliseconds | 0;

  var shouldEnd = start + milliseconds;
  try {
    childProcess.execFileSync(nodeBin, [ '-e',
      'setTimeout(function() {}, ' + shouldEnd + ' - Date.now());'
    ], {
      timeout: milliseconds,
    });
  } catch (ex) {
    if (ex.code !== 'ETIMEDOUT') {
      throw ex;
    }
  }
  var end = Date.now();
  return end - start;
}

Use timeout to handle very slow node on some platforms


$(function() {
  var $body    = $('body'),
      $caption = $('#caption'),
      $img     = $('#main-image');

  var getImage = (function() {
    var index     = 0,
        images    = [],
        lastCall  = Date.now(),
        WAIT_TIME = 1800000;  // 30 minutes

    function updateImages() {
      $.getJSON('media')
        .done(function(data) {
          index  = 0;
          images = data;
          lastCall = Date.now();
        })
        .fail(function(err) {
          console.log(err);
        });
    }

    updateImages();
    setInterval(updateImages, WAIT_TIME);

    return function getImage() {
      var image;

      if (images.length) {
        image = images[index];
        index = (index + 1) % images.length;
      }

      return image;
    };
  })();

  function changeImage() {
    var caption,
        duration = 5000,
        image    = getImage();

    if (image) {
      caption = image.caption || '';
      duration = image.duration || duration;

      $body.fadeOut(250, function() {
        $caption.text(caption);
        $img.one('load', function() {
          $body.fadeIn(250);
        }).attr('src', 'img/' + image.filename);
      });
    }

    setTimeout(changeImage, duration);
  }

  changeImage();
});

$(function() {
  var $body    = $('body'),
      $caption = $('#caption'),
      $img     = $('#main-image');

  var getImage = (function() {
    var index     = 0,
        images    = [],
        lastCall  = Date.now(),
        WAIT_TIME = 1800000;  // 30 minutes

    function updateImages() {
      $.getJSON('media')
        .done(function(data) {
          index  = 0;
          images = data;
          lastCall = Date.now();
        })
        .fail(function(err) {
          console.log(err);
        });
    }

    updateImages();
    setInterval(updateImages, WAIT_TIME);

    return function getImage() {
      var image;

      if (images.length) {
        image = images[index];
        index = (index + 1) % images.length;
      }

      return image;
    };
  })();

  function changeImage() {
    var caption,
        duration = 5000,
        image    = getImage();

    if (image) {
      caption = image.caption || '';
      duration = image.duration || duration;

      $body.fadeOut(250, function() {
        $caption.text(caption);

        $('img').remove();

        var img = $('<img id="main-image" class="main-image">');
        img.attr('src', 'img/' + image.filename);
        img.one('load', function() {
          $body.fadeIn(250);
        });
        img.prependTo('body');

        /*
        $img.one('load', function() {
          $body.fadeIn(250);
        }).attr('src', 'img/' + image.filename);
        */
      });
    }

    setTimeout(changeImage, duration);
  }

  changeImage();
});

Create a new image element instead of changing the image src. This is a potential fix to a memory issue in Chromium.