var redis = require('redis');
var util = require('util');

// ### Errors ###

function RedisConnectionError(error) {
	this.name = 'RedisConnectionError';
	this.message = error;
}
util.inherits(RedisConnectionError, Error);

function RedisAdapter() {
	this.client = redis.createClient();
}

RedisAdapter.prototype.connect = function () {
	var self = this;

	return function (req, res, next) {
		self.client.on('error', function (error) {
			throw new RedisConnectionError(error);
		});
		next();
	};
};

module.exports.RedisAdapter = RedisAdapter;

var redis = require('redis');
var util = require('util');

// ### Errors ###

function RedisConnectionError(error) {
	this.name = 'RedisConnectionError';
	this.message = error;
}
util.inherits(RedisConnectionError, Error);

function RedisAdapter() {
	this.client = redis.createClient();
	this.client.setMaxListeners(0);
}

RedisAdapter.prototype.connect = function () {
	var self = this;

	return function (req, res, next) {
		self.client.on('error', function (error) {
			throw new RedisConnectionError(error);
		});
		next();
	};
};

module.exports.RedisAdapter = RedisAdapter;

Set max listeners for redis client connection.


exports.up = function(knex, Promise) {
  return knex.schema.createTable('pages', function (table) {
    table.increments('id').primary()
    table.string('title')
    table.text('body', 'longtext')
    table.string('status')
    table.dateTime('published_date')
  })
};

exports.down = function(knex, Promise) {
  return knex.schema.dropTable('pages')
};

exports.up = function (knex, Promise) {
  return knex.schema.createTable('pages', function (table) {
    table.increments('id').primary()
    table.string('type')
    table.string('title')
    table.string('slug').unique()
    table.integer('author').unsigned()
    table.foreign('author').references('users.id')
    table.text('body', 'longtext')
    table.string('status')
    table.dateTime('published_date')
  })
}

exports.down = function (knex, Promise) {
  return knex.schema.dropTable('pages')
}

Add status, author and slug column to pages migration file


'use strict';

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

gulp.task('clean', function() {

  del([config.dist.root]);

});

'use strict';

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

gulp.task('clean', function(cb) {

  del([config.dist.root], cb);

});

Make tasks running in sequence


var pileup = require("pileup");

var sources = [
  {
    viz: pileup.viz.genome(),
    isReference: true,
    data: pileup.formats.twoBit({
      url: 'http://www.biodalliance.org/datasets/hg19.2bit'
    })
  },
  {
    viz: pileup.viz.variants(),
    data: pileup.formats.vcf({
      url: '/test/data/snv.chr17.vcf'
    })
  },
  {
    viz: pileup.viz.genes(),
    data: pileup.formats.bigBed({
      url: 'http://www.biodalliance.org/datasets/ensGene.bb'
    })
  },
  {
    viz: pileup.viz.pileup(),
    data: pileup.formats.bam({
      url: '/test/data/synth3.normal.17.7500000-7515000.bam',
      indexUrl: '/test/data/synth3.normal.17.7500000-7515000.bam.bai'
    }),
    cssClass: 'normal'
  }
];

var p = pileup.create(yourDiv, {
  range: {contig: 'chr17', start: 7512384, stop: 7512544},
  tracks: sources
});

var pileup = require("pileup");

var sources = [
  {
    viz: pileup.viz.genome(),
    isReference: true,
    data: pileup.formats.twoBit({
      url: 'http://www.biodalliance.org/datasets/hg19.2bit'
    }),
    name: 'Reference'
  },
  {
    viz: pileup.viz.variants(),
    data: pileup.formats.vcf({
      url: '/test/data/snv.chr17.vcf'
    }),
    name: 'Variants'
  },
  {
    viz: pileup.viz.genes(),
    data: pileup.formats.bigBed({
      url: 'http://www.biodalliance.org/datasets/ensGene.bb'
    }),
    name: 'Genes'
  },
  {
    viz: pileup.viz.pileup(),
    data: pileup.formats.bam({
      url: '/test/data/synth3.normal.17.7500000-7515000.bam',
      indexUrl: '/test/data/synth3.normal.17.7500000-7515000.bam.bai'
    }),
    cssClass: 'normal',
    name: 'Alignments'
  }
];

var p = pileup.create(yourDiv, {
  range: {contig: 'chr17', start: 7512384, stop: 7512544},
  tracks: sources
});

Set track labels in demo


const csvGenerator = {

}

export default csvGenerator;

const csvGenerator = {
	init() {
		const downloadCsvBtnEl = document.querySelector(".js-download-csv-btn");
		if (downloadCsvBtnEl) {
      downloadCsvBtnEl.addEventListener("click", e => {
      	window.open(window.location.href, '_blank');
      });
    }
	}
}

export default csvGenerator;

Handle download csv button click


// @flow
// complist reducers
import { ADD_COMPONENTS, ADD_TO_PROJECT } from '../actions/complist';
import getComponentLibrary from '../components/VisComponents/dataExporter';

type actionType = {+type: string,
};

const defaultData = getComponentLibrary();

// fs
//   .readdirSync('app/components/VisComponents/')
//   .filter(file => path.extname(file) === '.jsx')

export default function listReducer(state: {} = defaultData, action: actionType) {
  const newState = Object.assign({}, state);
  // newState.availableComponents =JSON.parse(JSON.stringify(newState.availableComponents));
  switch (action.type) {
    case ADD_COMPONENTS:
      return newState.availableComponents.concat(action.components);
    case ADD_TO_PROJECT:
      return newState;
    default:
      return newState;
  }
}

// @flow
// complist reducers
import { ADD_COMPONENTS, ADD_TO_PROJECT } from '../actions/complist';
import getComponentLibrary from '../components/VisComponents/dataExporter';

type actionType = {+type: string,
};

const defaultData = getComponentLibrary();

export default function listReducer(state: {} = defaultData, action: actionType) {
  const newState = Object.assign({}, state);

  switch (action.type) {
    case ADD_COMPONENTS:
      return newState.availableComponents.concat(action.components);
    case ADD_TO_PROJECT:
      return newState;
    default:
      return newState;
  }
}

Remove unneccessary commented out code


/**
 * Notify Store
 *
 * The notifications. Essentially a log to emit events.
 */

// Requires
import {ActionTypes} from '../constants/JWConstants.js';
import {register} from 'janeswalk/dispatcher/AppDispatcher';
import 'Store' from './Store.js';

// The notifications
const _log = [];

function receiveLogEntry(message, component, level) {
  _log.push({
    time: Date.now(),
    message: message,
    level: level
  });
}

const NotifyStore = Object.assign({}, Store, {
  getLog() {
    return _log;
  },

  // Register our dispatch token as a static method
  dispatchToken: register(function(payload) {
    // Go through the various actions
    switch(payload.type) {
      // Route actions
      case ActionTypes.LOG_INFO:
        receiveLogEntry(payload.message, payload.component || 'caw', 'info');
      NotifyStore.emitChange();
      break;
      case ActionTypes.LOG_WARN:
        receiveLogEntry(payload.message, payload.component || 'caw', 'warn');
      NotifyStore.emitChange();
      break;
      case ActionTypes.LOG_ERROR:
        receiveLogEntry(payload.message, payload.component || 'caw', 'error');
      NotifyStore.emitChange();
      break;
      default:
        // do nothing
    }
  });
});

export default NotifyStore;

/**
 * Notify Store
 *
 * The notifications. Essentially a log to emit events.
 */

// Requires
import {register2} from 'janeswalk/dispatcher/AppDispatcher';
import {EventEmitter} from 'events';
import {ActionTypes as AT} from 'janeswalk/constants/JWConstants';
import {changeMethods} from 'janeswalk/utils/Stores';

// The notifications
const _log = [];

function receiveLogEntry(message, component, level) {
  _log.push({
    time: Date.now(),
    message: message,
    level: level
  });
}

const NotifyStore = Object.assign({}, EventEmitter.prototype, changeMethods {
  getLog: () => _log,
  getLogFrom: (from) => _log.filter(entry => entry.time >= from),

  // Register our dispatch token as a static method
  dispatchToken: register2({
    [AT.LOG_INFO]: ({message, component}) => {
      receiveLogEntry(payload.message, payload.component || 'caw', 'info');
    },
    [AT.LOG_WARN]: ({message, component}) => {
      receiveLogEntry(message, component || 'caw', 'warn');
    },
    [AT.LOG_ERROR]: ({message, component}) => {
      receiveLogEntry(message, component || 'caw', 'error');
    },
    [AT.LOG_EMPTY]: () => _log.splice(0),
  }, () => NotifyStore.emitChange())
});

export default NotifyStore;

Convert notify store to new pattern


// N E T W O R K    S E R V I C E

describe('NetworkService Unit Tests', function(){
  beforeEach(module('starter.services'));

  beforeEach(inject(function (_$rootScope_, _NetworkService_) {
    NetworkService = _NetworkService_;
    $rootScope = _$rootScope_;

    localStorage.removeItem('networkStatus');
  }));

  it('should set localStorage["networkStatus"] to offline', function(){
    NetworkService.networkEvent('offline');
    expect(localStorage['networkStatus']).toBe("offline");
  });

  it('should set localStorage["networkStatus"] to online and not sync', function(){
    localStorage.setItem('networkStatus', 'online');
    NetworkService.networkEvent('online');
    expect(localStorage['networkStatus']).toBe("online");
  });

});

// N E T W O R K    S E R V I C E

describe('NetworkService Unit Tests', function(){
  beforeEach(module('starter.services'));

  beforeEach(inject(function (_$rootScope_, _NetworkService_) {
    NetworkService = _NetworkService_;
    $rootScope = _$rootScope_;

    localStorage.removeItem('networkStatus');
  }));

  it('should set localStorage["networkStatus"] to offline', function(){
    NetworkService.networkEvent('offline');
    expect(localStorage.getItem('networkStatus')).toBe("offline");
  });

  it('should set localStorage["networkStatus"] to online and not sync', function(){
    localStorage.setItem('networkStatus', 'online');
    NetworkService.networkEvent('online');
    expect(localStorage.getItem('networkStatus')).toBe("online");
  });

});

Move to got notation following JS hinting


const syrup = require('../../');

syrup.enableDebug()
    .config(`${__dirname}/config.yaml`)
    .scenario({
        name: 'snippets - 1',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'ChromeBrowser'
    })
    .scenario({
        name: 'snippets - 2',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'ChromeBrowser'
    })
    .scenario({
        name: 'snippets - 3',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'ChromeBrowser'
    })
    .scenario({
        name: 'snippets - 4',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'ChromeBrowser'
    })
    .pour();

const syrup = require('../../');

syrup.enableDebug()
    .config(`${__dirname}/config.yaml`)
    .scenario({
        name: 'snippets - 1',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'PhantomJsBrowser'
    })
    .scenario({
        name: 'snippets - 2',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'PhantomJsBrowser'
    })
    .scenario({
        name: 'snippets - 3',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'PhantomJsBrowser'
    })
    .scenario({
        name: 'snippets - 4',
        entrypoint: `${__dirname}/test-snippets`,
        dependsOn: [],
        worker: 'PhantomJsBrowser'
    })
    .pour();

Use phantomjs for snippets testing


// report.js -- Report of the results of a batch and its sub-batches
//
// Copyright 2017 fuzzy.ai <evan@fuzzy.ai>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* jshint esversion: 6 */

class Report {
  constructor(title) {
    this.title = title
    this.broken = 0
    this.successes = 0
    this.failures = 0
    this.tests = {}
    this.subs = {}
  }
}

module.exports = Report

// report.js -- Report of the results of a batch and its sub-batches
//
// Copyright 2017 fuzzy.ai <evan@fuzzy.ai>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* jshint esversion: 6 */

'use strict';

class Report {
  constructor(title) {
    this.title = title
    this.broken = 0
    this.successes = 0
    this.failures = 0
    this.tests = {}
    this.subs = {}
  }
}

module.exports = Report

Fix strictness error when using node 4


var config = require('../settings.json'),
    log4js = require('log4js').getLogger(),
    fs = require('fs');

module.exports = {
    logger: {
        debug: (log) => {
            log4js.debug(log);
        },
        error: (log) => {
            log4js.error(log);
        }
    },
    // steps -> how many times to call
    // speed -> the FPS
    preciseSetTimeout: (steps, speed, oninstance, oncomplete) => {
        var count = 0,
            start = new Date().getTime();

        function loop() {
            if (count++ >= steps) {
                oncomplete()
            } else {
                oninstance(count);
                var diff = (new Date().getTime() - start) - (count * speed);
                setTimeout(loop, (speed - diff));
            }
        }
        setTimeout(loop, speed);
    },
    quatInverse: (q) => {
        var len = Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
        return {
            w: q.w / len,
            x: -q.x / len,
            y: -q.y / len,
            z: -q.z / len
        };
    },
    clearTimers: (animation) => {
        var noop = () => {};
        Object.keys(animation).forEach((key) => {
            if (key == 'TIMERS') {
                animation[key].forEach((timer) => {
                    clearTimeout(timer);
                });
            }
            animation[key] = noop;
        });
        animation = null;
    }
}

var config = require('../settings.json'),
    log4js = require('log4js').getLogger(),
    fs = require('fs');

module.exports = {
    logger: {
        debug: (log) => {
            log4js.debug(log);
        },
        error: (log) => {
            log4js.error(log);
        }
    },
    // steps -> how many times to call
    // speed -> the FPS
    preciseSetTimeout: (steps, speed, oninstance, oncomplete) => {
        var count = 0,
            start = new Date().getTime();

        function loop() {
            if (count++ >= steps) {
                oncomplete()
            } else {
                oninstance(count);
                var diff = (new Date().getTime() - start) - (count * speed);
                setTimeout(loop, (speed - diff));
            }
        }
        setTimeout(loop, speed);
    },
    quatInverse: (q) => {
        var len = Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
        return {
            w: q.w / len,
            x: -q.x / len,
            y: -q.y / len,
            z: -q.z / len
        };
    },
    clearTimers: (animation) => {
        var noop = () => {};
        Object.keys(animation).forEach((key) => {
            if (key == 'TIMERS' && Array.isArray(animation[key])) {
                animation[key].forEach((timer) => {
                    clearTimeout(timer);
                });
            }
            animation[key] = noop;
        });
        animation = null;
    }
}

Check for array before forEach


import { EventEmitter } from 'events'
import axios from 'axios'

export default class RoomService extends EventEmitter {
  constructor() {
    super()
  }

  addRoom(timeslots) {
    this.createRoom(room, this.hasBeenAdded.bind(this), this.getThem.bind(this))
  }

  getThem(userid) {
    this.getRooms(userid, this.gotthem.bind(this))
  }

  createRoom(interviewer, roomid, callback) {
    axios.post('/api/Meeting', {
        owner_id: interviewer,
        room_url:,
        time:
    })
    .then(function (response) {
      console.log(response)
      callback()

    })
    .catch(function (error) {
      console.log(error);
    });
  }

  getRooms(userid, callback) {
    axios.get('/api/Meeting', {
      params: {
        owner_id: userid
      }
    })
    .then(function (response) {
      response.data.forEach(function(slot) {
        slot.start = new Date(slot.start)
        slot.end = new Date(slot.end)
      })

      callback(response)
      //this.gotthem(reponse).bind(this)
      console.log('got slots', response);
      console.log('got slots', response.data);

    })
    .catch(function (error) {
      console.log(error);
    });
  }
  hasBeenAdded(slots) {
    this.emit('rooms_added', slots)
  }
  gotthem(slots) {
    this.emit('got_rooms', slots)
  }

}

import { EventEmitter } from 'events'
import axios from 'axios'

export default class RoomService extends EventEmitter {
  constructor() {
    super()
  }

  addRoom(timeslots) {
    this.createRoom(room, this.hasBeenAdded.bind(this), this.getThem.bind(this))
  }

  getThem(userid) {
    this.getRooms(userid, this.gotthem.bind(this))
  }

  createRoom(interviewer, roomid, callback) {
    axios.post('/api/Meeting', {
        owner_id: interviewer,
        job_position: 'janitor'
    })
    .then(function (response) {
      console.log(response)
      callback()

    })
    .catch(function (error) {
      console.log(error);
    });
  }

  getRooms(userid, callback) {
    axios.get('/api/Meeting', {
      params: {
        owner_id: userid
      }
    })
    .then(function (response) {
      response.data.forEach(function(slot) {
        slot.start = new Date(slot.start)
        slot.end = new Date(slot.end)
      })

      callback(response)
      //this.gotthem(reponse).bind(this)
      console.log('got slots', response);
      console.log('got slots', response.data);

    })
    .catch(function (error) {
      console.log(error);
    });
  }
  hasBeenAdded(slots) {
    this.emit('rooms_added', slots)
  }
  gotthem(slots) {
    this.emit('got_rooms', slots)
  }

}

Fix error typo and changed post request to use expected request body


/**
 *  Assigns handlers/listeners for `[data-action]` links.
 *
 *  Actions associated with a link will be invoked via Wire with the jQuery
 *  event object as an argument.
 **/

'use strict';

/*global NodecaLoader, N, window*/

var $ = window.jQuery;

$(function () {
  ['click', 'submit', 'input'].forEach(function (action) {
    var eventName = action + '.nodeca.data-api'
      , attribute = '[data-on-' + action + ']';

    $('body').on(eventName, attribute, function (event) {
      var apiPath = $(this).data('on-' + action);

      NodecaLoader.loadAssets(apiPath.split('.').shift(), function () {
        if (N.wire.has(apiPath)) {
          N.wire.emit(apiPath, event);
        } else {
          N.logger.error('Unknown client Wire handler: %s', apiPath);
        }
      });

      event.preventDefault();
      return false;
    });
  });
});

/**
 *  Assigns handlers/listeners for `[data-action]` links.
 *
 *  Actions associated with a link will be invoked via Wire with the jQuery
 *  event object as an argument.
 **/

'use strict';

/*global NodecaLoader, N, window*/

var $ = window.jQuery;

$(function () {
  ['click', 'submit', 'input', 'change'].forEach(function (action) {
    var eventName = action + '.nodeca.data-api'
      , attribute = '[data-on-' + action + ']';

    $('body').on(eventName, attribute, function (event) {
      var apiPath = $(this).data('on-' + action);

      NodecaLoader.loadAssets(apiPath.split('.').shift(), function () {
        if (N.wire.has(apiPath)) {
          N.wire.emit(apiPath, event);
        } else {
          N.logger.error('Unknown client Wire handler: %s', apiPath);
        }
      });

      event.preventDefault();
      return false;
    });
  });
});

Add DOM's `change` event for client-side UJS handlers.


'use strict';
var through = require('through2');
var formatAddress = require('../lib/formatAddress');

module.exports = function(addr, city, state, zip){
  if(!addr) throw new Error('Must provide address at minimum.');
  var args = [addr, city, state, zip];
  var prefix = '';
  var suffix = '';

  //Chunk is a GeoJSON feature
  function transform(chunk, enc, cb){
    chunk = JSON.parse(chunk);
    var props = chunk.properties;
    var payload;

    try{

      var vals = args.map(function(arg){
        if(typeof arg === 'function') return arg(props);
        return props[arg];
      });

      payload = {
        type: "Feature",
        properties: {
          address: formatAddress(
                       vals[0],
                       vals[1],
                       vals[2],
                       vals[3]
                       ),
          alt_address: "",
          load_date: Date.now()
          //Source<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        },
        geometry: {
          type: "Point",
          coordinates: chunk.geometry.coordinates
        }
      };

    }catch(e){
      //possibly log the error
      return cb();
    }
    //Elaticsearch bulk wants newline separated values
    this.push(prefix + JSON.stringify(payload) + suffix);
    cb();
  }

  return function(pre, suf){
    if(pre) prefix = pre;
    if(suf) suffix = suf;
    return through(transform);
  }
};

'use strict';
var through = require('through2');
var formatAddress = require('../lib/formatAddress');

var loadDate = Date.now();

module.exports = function(addr, city, state, zip){
  if(!addr) throw new Error('Must provide address at minimum.');
  var args = [addr, city, state, zip];
  var prefix = '';
  var suffix = '';

  //Chunk is a GeoJSON feature
  function transform(chunk, enc, cb){
    chunk = JSON.parse(chunk);
    var props = chunk.properties;
    var payload;

    try{

      var vals = args.map(function(arg){
        if(typeof arg === 'function') return arg(props);
        return props[arg];
      });

      payload = {
        type: "Feature",
        properties: {
          address: formatAddress(
                       vals[0],
                       vals[1],
                       vals[2],
                       vals[3]
                       ),
          alt_address: "",
          load_date: loadDate
          //Source<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        },
        geometry: {
          type: "Point",
          coordinates: chunk.geometry.coordinates
        }
      };

    }catch(e){
      //possibly log the error
      return cb();
    }
    //Elaticsearch bulk wants newline separated values
    this.push(prefix + JSON.stringify(payload) + suffix);
    cb();
  }

  return function(pre, suf){
    if(pre) prefix = pre;
    if(suf) suffix = suf;
    return through(transform);
  }
};

Change load date to be constant per loading event


{
    let util = {};
    Components.utils.import("resource://gipsy/util.jsm", util);

    let myId    = "gipsy-button"; // ID of button to add
    let afterId = "search-container";    // ID of element to insert after
    let navBar  = document.getElementById("nav-bar");

    if (navBar && !util.get_bool_pref('btn_toolbar_added')) {
        let curSet  = navBar.currentSet.split(",");
        if (curSet.indexOf(myId) == -1) {
            let pos = curSet.indexOf(afterId) + 1 || curSet.length;
            let set = curSet.slice(0, pos).concat(myId).concat(curSet.slice(pos));

            navBar.setAttribute("currentset", set.join(","));
            navBar.currentSet = set.join(",");
            document.persist(navBar.id, "currentset");
            try {
                BrowserToolboxCustomizeDone(true);
            } catch (e) {}
            util.set_bool_pref('btn_toolbar_added', true);
        }
    }
}

{
    let GipsyUtil = {};
    Components.utils.import("resource://gipsy/util.jsm", GipsyUtil);

    let myId    = "gipsy-button"; // ID of button to add
    let afterId = "search-container";    // ID of element to insert after
    let navBar  = document.getElementById("nav-bar");

    if (navBar && !GipsyUtil.get_bool_pref('btn_toolbar_added')) {
        let curSet  = navBar.currentSet.split(",");
        if (curSet.indexOf(myId) == -1) {
            let pos = curSet.indexOf(afterId) + 1 || curSet.length;
            let set = curSet.slice(0, pos).concat(myId).concat(curSet.slice(pos));

            navBar.setAttribute("currentset", set.join(","));
            navBar.currentSet = set.join(",");
            document.persist(navBar.id, "currentset");
            try {
                BrowserToolboxCustomizeDone(true);
            } catch (e) {}
            GipsyUtil.set_bool_pref('btn_toolbar_added', true);
        }
    }
}

Rename 'util' to 'GipsyUtil' in overlay.


var WebPage = require('webpage');
var System = require('system');
address = System.args[1];
var index = 0;

var screenshots = [
  {"dimensions" : [975,500],
  "filename": './screenshots/screenshot_l.png'},
  {"dimensions" : [720,400],
  "filename": './screenshots/screenshot_m.png'},
  {"dimensions" : [400,200],
  "filename": './screenshots/screenshot_s.png'}
];

var capturescreen = function(dimensions, filename){
  var page = WebPage.create();
  page.viewportSize = {
    width: dimensions[0],
    height: dimensions[1]
  };
  page.open(address);
  page.onLoadFinished = setTimeout(function() {
      page.render(filename);
      page.close();
      index++;
      // Give it a second before calling next.
      // Phantom runs into some sort of race condition without this
      setTimeout(nextPage, 1000);
  }, 3000);
}

var nextPage = function(){
  if(!screenshots[index]){
    phantom.exit();
  }
  capturescreen(screenshots[index].dimensions, screenshots[index].filename);
}

nextPage();

var WebPage = require('webpage'),
    System = require('system'),
    address = System.args[1],
    index = 0;

// All the sizes to screenshot.
// Note: PhantomJs uses the heights specified here as a min-height criteria
var screenshots = [
  {"dimensions" : [970,300],
  "filename": './screenshots/screenshot_l.png'},
  {"dimensions" : [720,300],
  "filename": './screenshots/screenshot_m.png'},
  {"dimensions" : [400,200],
  "filename": './screenshots/screenshot_s.png'}
];

var capturescreen = function(dimensions, filename){
  var page = WebPage.create();
  page.viewportSize = {
    width: dimensions[0],
    height: dimensions[1]
  };
  page.open(address);
  page.onLoadFinished = setTimeout(function() {
      page.render(filename);
      page.close();
      index++;

      // Give it a second before calling next.
      // Phantom runs into some sort of race condition without this
      setTimeout(nextPage, 1000);
  }, 3000);
}

var nextPage = function(){
  if(!screenshots[index]){
    phantom.exit();
  }
  capturescreen(screenshots[index].dimensions, screenshots[index].filename);
}

nextPage();

Add height is not absoulte note


import {encrypt} from '../../kms';

export default async (req, res, next) => {
  const plaintext = req.body.secret;
  let keyObj;

  try {
    keyObj = JSON.parse(req.body.key);
  } catch (err) {
    console.log(err);
    keyObj = null;
  }

  if (!keyObj) {
    return next(new Error('CMK not defined'));
  }

  if (!plaintext) {
    return next(new Error('Plaintext not entered'));
  }

  const region = keyObj.region;
  const key = keyObj.key;
  const params = {
    KeyId: key,
    Plaintext: plaintext,
    region
  };

  let data;

  try {
    data = await encrypt(params);
  } catch (err) {
    return next(err);
  }

  const resp = {
    region: data.region
  };

  if (data instanceof Error) {
    resp.status = 'ERROR';
    resp.text = data.message;
  } else {
    resp.status = 'SUCCESS';
    resp.text = `$tokend:
type: kms
resource: /v1/kms/decrypt
region: ${data.region}
ciphertext: "${data.ciphertext}"
datakey: "${data.datakey}"`;
  }

  return res.json(resp);
};

import {encrypt} from '../../kms';

export default async (req, res, next) => {
  const plaintext = req.body.secret;
  let keyObj;

  try {
    keyObj = JSON.parse(req.body.key);
  } catch (err) {
    console.log(err);
    keyObj = null;
  }

  if (!keyObj) {
    return next(new Error('CMK not defined'));
  }

  if (!keyObj.hasOwnProperty('region') || !keyObj.hasOwnProperty('key')) {
    return next(new Error('Invalid key format'));
  }

  if (!plaintext) {
    return next(new Error('Plaintext not entered'));
  }

  const region = keyObj.region;
  const key = keyObj.key;
  const params = {
    KeyId: key,
    Plaintext: plaintext,
    region
  };

  let data;

  try {
    data = await encrypt(params);
  } catch (err) {
    return next(err);
  }

  const resp = {
    region: data.region
  };

  if (data instanceof Error) {
    resp.status = 'ERROR';
    resp.text = data.message;
  } else {
    resp.status = 'SUCCESS';
    resp.text = `$tokend:
type: kms
resource: /v1/kms/decrypt
region: ${data.region}
ciphertext: "${data.ciphertext}"
datakey: "${data.datakey}"`;
  }

  return res.json(resp);
};

Add validation for the key submitted in the POST body.


// app.shoppingListService.js

(function() {
  "use strict";

  angular.module("MyApp")
    .service("ShoppingListService", ShoppingListService);

  ShoppingListService.$inject = ["$q", "WeightLossFilterService"];

  function ShoppingListService($q, WeightLossFilterService) {
    let service = this;

    // List of Shopping items
    let items = [];

    service.addItem = addItem;

    function addItem(itemName, itemQuantity) {
      let promise = WeightLossFilterService.checkName(itemName);

      promise.then(response => {
        let nextPromise = WeightLossFilterService.checkQuantity(itemQuantity);

        nextPromise.then(result => {
          let item = {
            name: itemName,
            quantity: itemQuantity
          };

          items.push(item);
        }, errorResponse => {
          console.log(errorResponse.message);
        });
      }, errorResponse => {
        console.log(errorResponse.message);
      });
    }
  }
})();

// app.shoppingListService.js

(function() {
  "use strict";

  angular.module("ShoppingListApp")
    .service("ShoppingListService", ShoppingListService);

  ShoppingListService.$inject = ["$q", "WeightLossFilterService"];

  function ShoppingListService($q, WeightLossFilterService) {
    let service = this;

    // List of Shopping items
    let items = [];

    service.addItem = addItem;
    service.getItems = getItems;

    function addItem(itemName, itemQuantity) {
      let promise = WeightLossFilterService.checkName(itemName);

      promise.then(response => {
        let nextPromise = WeightLossFilterService.checkQuantity(itemQuantity);

        nextPromise.then(result => {
          let item = {
            name: itemName,
            quantity: itemQuantity
          };

          items.push(item);
        }, errorResponse => {
          console.log(errorResponse.message);
        });
      }, errorResponse => {
        console.log(errorResponse.message);
      });
    }

    function getItems() {
      return items;
    }
  }
})();

Change app name. Added getItems method


describe("Pages publication", function() {
  beforeEach(function (done) {
    Meteor.call('fixtures/reset', done);
  });

  it('should return regular data but not premiumContent when a user is not logged in', function() {
    //Setup
    Letterpress.Collections.Pages.insert({
      _id: 'myId',
      title: 'My Title with Spaces and Cases',
      content: 'My preview content',
      premiumContent: 'My premium content that you need to login for',
      order: 1,
      path: '/content'
    });
    //Execute
    var cursor = Meteor.server.publish_handlers.pages();
    //Verify
    data = cursor.fetch()[0];
    expect(data.premiumContent).toBeUndefined;
    expect(data.content).toBe('My preview content');
    expect(data.title).toBe('My Title with Spaces and Cases');
    expect(data.order).toBe(1);
    expect(data.path).toBe("/content");
  });

  it('should return premiumContent when a user is logged in', function() {
    //Setup
    Letterpress.Collections.Pages.insert({
      _id: 'myId',
      title: 'My Title with Spaces and Cases',
      content: 'My preview content',
      premiumContent: 'My premium content that you need to login for'
    });
    //Execute
    var cursor = Meteor.server.publish_handlers.pages.apply({userId: '123'});
    //Verify
    expect(cursor.fetch()[0].premiumContent).toBe('My premium content that you need to login for');
  });
});

describe("Pages publication", function() {
  beforeEach(function (done) {
    Meteor.call('fixtures/reset', function() {
      Letterpress.Collections.Pages.insert({
        _id: 'myId',
        title: 'My Title with Spaces and Cases',
        content: 'My preview content',
        premiumContent: 'My premium content that you need to login for',
        order: 1,
        path: '/content'
      }, done);
    });
  });

  it('should return regular data but not premiumContent when a user is not logged in', function() {
    //Setup
    var page = Letterpress.Collections.Pages.findOne('myId');
    //Execute
    var cursor = Meteor.server.publish_handlers.pages();
    //Verify
    data = cursor.fetch()[0];
    expect(data.premiumContent).toBeUndefined;
    expect(data.content).toBe(page.content);
    expect(data.title).toBe(page.title);
    expect(data.order).toBe(page.order);
    expect(data.path).toBe(page.path);
  });

  it('should return premiumContent when a user is logged in', function() {
    //Setup
    var page = Letterpress.Collections.Pages.findOne('myId');
    //Execute
    var cursor = Meteor.server.publish_handlers.pages.apply({userId: '123'});
    //Verify
    expect(cursor.fetch()[0].premiumContent).toBe(page.premiumContent);
  });
});

Clean up the tests a bit to read easier. Also DRY.


import FilterableList from '~/filterable_list';

export default class GroupFilterableList extends FilterableList {
  constructor(form, filter, holder, store) {
    super(form, filter, holder);

    this.store = store;
    this.$dropdown = $('.js-group-filter-dropdown-wrap');
  }

  bindEvents() {
    super.bindEvents();

    this.onFormSubmitWrapper = this.onFormSubmit.bind(this);
    this.onFilterOptionClikWrapper = this.onOptionClick.bind(this);

    this.filterForm.addEventListener('submit', this.onFormSubmitWrapper);
    this.$dropdown.on('click', 'a', this.onFilterOptionClikWrapper);
  }

  onFormSubmit(e) {
    e.preventDefault();

    this.filterResults();
  }

  onOptionClick(e) {
    e.preventDefault();
    const currentOption = $.trim(e.currentTarget.text);

    this.filterUrl = e.currentTarget.href;
    this.$dropdown.find('.dropdown-label').text(currentOption);
    this.filterResults(this.filterUrl);
  }

  onFilterSuccess(data) {
    super.onFilterSuccess(data);

    this.store.setGroups(data);
  }
}

import FilterableList from '~/filterable_list';

export default class GroupFilterableList extends FilterableList {
  constructor(form, filter, holder, store) {
    super(form, filter, holder);

    this.store = store;
    this.$dropdown = $('.js-group-filter-dropdown-wrap');
  }

  bindEvents() {
    super.bindEvents();

    this.onFormSubmitWrapper = this.onFormSubmit.bind(this);
    this.onFilterOptionClikWrapper = this.onOptionClick.bind(this);

    this.filterForm.addEventListener('submit', this.onFormSubmitWrapper);
    this.$dropdown.on('click', 'a', this.onFilterOptionClikWrapper);
  }

  onFormSubmit(e) {
    e.preventDefault();

    this.filterResults();
  }

  onOptionClick(e) {
    e.preventDefault();
    const currentOption = $.trim(e.currentTarget.text);

    this.filterUrl = e.currentTarget.href;
    this.$dropdown.find('.dropdown-label').text(currentOption);
    this.filterResults(this.filterUrl);
  }

  onFilterSuccess(data, textStatus, xhr) {
    super.onFilterSuccess(data);

    this.store.setGroups(data);
    this.store.storePagination({
      'X-Per-Page': xhr.getResponseHeader('X-Per-Page'),
      'X-Page': xhr.getResponseHeader('X-Page'),
      'X-Total': xhr.getResponseHeader('X-Total'),
      'X-Total-Pages': xhr.getResponseHeader('X-Total-Pages'),
      'X-Next-Page': xhr.getResponseHeader('X-Next-Page'),
      'X-Prev-Page': xhr.getResponseHeader('X-Prev-Page'),
    });
  }
}

Fix pagination when sorting by option


"use strict";

(function() {

var REMOTE_URL = "http://localhost:48278/";

musicd.RemoteControl = function(player) {
    this._player = player;
    this._player.state.subscribe(this._updateState, this);
};

musicd.RemoteControl.prototype = {
    enable: function() {
        if (this.eventSource)
            return;

        this.eventSource = new EventSource(REMOTE_URL + "events");
        this.eventSource.addEventListener("command", this._command.bind(this));
        this.eventSource.onopen = this._updateState.bind(this);

        this._updateState();
    },

    disable: function() {
        if (this.eventSource) {
            this.eventSource.close();
            this.eventSource = null;
        }
    },

    _updateState: function() {
        if (this.eventSource)
            $.post(REMOTE_URL + "state/" + musicd.PlayerState[this._player.state()].toLowerCase());
    },

    _command: function(e) {
        if (this.eventSource)
            this._player.execCommand(e.data);
    }
};

})();

"use strict";

(function() {

var REMOTE_URL = "http://localhost:48278/";

musicd.RemoteControl = function(player) {
    this._player = player;
    this._player.state.subscribe(this._updateState, this);
    this._player.track.subscribe(this._updateTrack, this);
};

musicd.RemoteControl.prototype = {
    enable: function() {
        if (this.eventSource)
            return;

        this.eventSource = new EventSource(REMOTE_URL + "events");
        this.eventSource.addEventListener("command", this._command.bind(this));
        this.eventSource.onopen = this._updateAll.bind(this);

        this._updateAll();
    },

    disable: function() {
        if (this.eventSource) {
            this.eventSource.close();
            this.eventSource = null;
        }
    },

    _updateAll: function() {
        this._updateState();
        this._updateTrack();
    },

    _updateState: function() {
        if (!this.eventSource)
            return;

        $.post(REMOTE_URL + "state/" + musicd.PlayerState[this._player.state()].toLowerCase());
    },

    _updateTrack: function() {
        if (!this.eventSource)
            return;

        var track = this._player.track(),
            url = REMOTE_URL + "track";

        if (track) {
            url += "?id=" + track.id
                + "&title=" + encodeURIComponent(track.title)
                + "&artist=" + encodeURIComponent(track.artist)
                + "&album=" + encodeURIComponent(track.album)
                + "&duration=" + encodeURIComponent(track.duration);
        } else {
            url += "?id=0";
        }

        $.post(url);
    },

    _command: function(e) {
        if (!this.eventSource)
            return;

        this._player.execCommand(e.data);
    }
};

})();

Send current track information to remote control


function rememberScrollPosition() {
    function rememberScrollPositionForElement(element) {
        var id = element.getAttribute('id');
        var scrollTimer;
        element.onscroll = function (e) {
            clearTimeout(scrollTimer);
            scrollTimer = setTimeout(function () {
                localStorage.setItem(id + ' scrollTop', element.scrollTop);
                localStorage.setItem(id + ' scrollLeft', element.scrollLeft);
            }, 1000);
        };
    }
    function retrieveScrollPositionForElement(element) {
        var id = element.getAttribute('id');
        var scrollTop = localStorage.getItem(id + ' scrollTop');
        var scrollLeft = localStorage.getItem(id + ' scrollLeft');
        if (typeof scrollTop === 'string') {
            element.scrollTop = parseInt(scrollTop, 10);
            element.scrollLeft = parseInt(scrollLeft, 10);
        }
    }

    var elements = document.querySelectorAll('.js-remember-scroll-position');
    for (var i = 0; i < elements.length; i += 1) {
        try {
            var element = elements[i];
            retrieveScrollPositionForElement(element);
            rememberScrollPositionForElement(element);
        } catch (e) {
            // ignore
        }
    }
}

rememberScrollPosition();

function rememberScrollPosition() {
    function rememberScrollPositionForElement(element) {
        var id = element.getAttribute('id');
        var scrollTimer;
        element.onscroll = function (e) {
            clearTimeout(scrollTimer);
            scrollTimer = setTimeout(function () {
                localStorage.setItem(id + ' scrollTop', element.scrollTop);
                localStorage.setItem(id + ' scrollLeft', element.scrollLeft);
            }, 300);
        };
    }
    function retrieveScrollPositionForElement(element) {
        var id = element.getAttribute('id');
        var scrollTop = localStorage.getItem(id + ' scrollTop');
        var scrollLeft = localStorage.getItem(id + ' scrollLeft');
        if (typeof scrollTop === 'string') {
            element.scrollTop = parseInt(scrollTop, 10);
            element.scrollLeft = parseInt(scrollLeft, 10);
        }
    }

    var elements = document.querySelectorAll('.js-remember-scroll-position');
    for (var i = 0; i < elements.length; i += 1) {
        try {
            var element = elements[i];
            retrieveScrollPositionForElement(element);
            rememberScrollPositionForElement(element);
        } catch (e) {
            // ignore
        }
    }
}

rememberScrollPosition();

Save the scroll position more often


import { extend } from 'flarum/extend';
import PermissionGrid from 'flarum/components/PermissionGrid';

export default function() {
  extend(PermissionGrid.prototype, 'moderateItems', items => {
    items.add('tag', {
      label: 'Edit tags',
      permission: 'discussion.tag'
    });
  });
}

import { extend } from 'flarum/extend';
import PermissionGrid from 'flarum/components/PermissionGrid';

export default function() {
  extend(PermissionGrid.prototype, 'moderateItems', items => {
    items.add('tag', {
      label: 'Tag discussions',
      permission: 'discussion.tag'
    });
  });
}

Use more intuitive permission description


import getFreeBinding from '../utils/getFreeBinding';

/**
 * Convert binary existential operators, e.g. `a ? b` into `if` expressions
 * using unary existential operators, e.g. `if a? then a else b`.
 *
 * @param {Object} node
 * @param {MagicString} patcher
 */
export default function preprocessBinaryExistentialOperator(node, patcher) {
  if (node.type === 'ExistsOp') {
    // e.g. `if a? then a else b`
    //       ^^^
    patcher.insert(node.range[0], 'if ');

    if (node.left.type === 'Identifier') {
      // e.g. `a ? b` -> `if a? then a else b`
      //        ^^^           ^^^^^^^^^^^^^^
      patcher.replace(node.range[0], node.range[1], `${node.left.raw}? then ${node.left.raw} else ${node.right.raw}`);
    } else {
      let tmp = getFreeBinding(node.scope);
      // e.g. `@a ? @b` -> `if (ref = @a)? then ref else @b`
      //       ^^^^^           ^^^^^^^^^^^^^^^^^^^^^^^^^^
      patcher.replace(node.range[0], node.range[1], `(${tmp} = ${node.left.raw})? then ${tmp} else ${node.right.raw}`);
    }

    return true;
  }
}

import getFreeBinding from '../utils/getFreeBinding';

/**
 * Convert binary existential operators, e.g. `a ? b` into `if` expressions
 * using unary existential operators, e.g. `if a? then a else b`.
 *
 * @param {Object} node
 * @param {MagicString} patcher
 */
export default function preprocessBinaryExistentialOperator(node, patcher) {
  if (node.type === 'ExistsOp') {
    // e.g. `if a? then a else b`
    //       ^^^
    patcher.insert(node.range[0], 'if ');

    if (node.left.type === 'Identifier') {
      // e.g. `a ? b` -> `if a? then a else b`
      //       ^^^^^         ^^^^^^^^^^^^^^^^
      patcher.replace(node.range[0], node.range[1], `${node.left.raw}? then ${node.left.raw} else ${node.right.raw}`);
    } else {
      let tmp = getFreeBinding(node.scope);
      // e.g. `@a ? @b` -> `if (ref = @a)? then ref else @b`
      //       ^^^^^^^         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      patcher.replace(node.range[0], node.range[1], `(${tmp} = ${node.left.raw})? then ${tmp} else ${node.right.raw}`);
    }

    return true;
  }
}

Update the comment ranges to reflect the new replacements.


var _ = require('lodash'),
  net = require('net');

function Client (opts) {
  opts = _.defaults(_.pick(opts, Object.keys(Client.defaults)), Client.defaults);

  for (var key in opts) {
    Object.defineProperty(this, key, { value: opts[key] })
  }
}

Client.prototype.connect = function () {
  return this.socket = net.connect({ host: this.host, port: this.port });
}

Client.defaults = {
  host: '127.0.0.1',
  port: 2003
}

module.exports = Client;

var _ = require('lodash'),
  dgram = require('dgram');

function Client (opts) {
  opts = _.defaults(_.pick(opts, Object.keys(Client.defaults)), Client.defaults);

  for (var key in opts) {
    Object.defineProperty(this, key, { value: opts[key] })
  }
}

Client.prototype.connect = function () {
  return this.socket = dgram.createSocket(this.type);
}

Client.defaults = {
  host: '127.0.0.1',
  port: 2003,
  type: 'udp4'
}

module.exports = Client;

Switch to using a dgram socket


function clampIntRange(num, min, max) {
  num = Math.floor(num);
	if (num < min) num = min;
	if (typeof max !== 'undefined' && num > max) num = max;
	return num;
}
exports.BattleStatuses = {
};

function clampIntRange(num, min, max) {
  num = Math.floor(num);
	if (num < min) num = min;
	if (typeof max !== 'undefined' && num > max) num = max;
	return num;
}
exports.BattleStatuses = {
	frz: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target, 'frz');
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon, target, move) {
			if (move.thawsUser || this.random(2) === 0) {
				pokemon.cureStatus();
				return;
			}
			this.add('cant', pokemon, 'frz');
			return false;
		},
		onHit: function(target, source, move) {
			if (move.type === 'Fire' && move.category !== 'Status') {
				target.cureStatus();
			}
		}
	},
	hail: {
		inherit: true,
		onModifyDef: function(def, pokemon) {
			if (pokemon.hasType('Ice') && this.isWeather('hail')) {
				return def * 3/2;
			}
		}
	}
};

Add Freeze and Hail changes


// Time-stamp: "2018-04-14 21:07:05 phil"

dumpln("50os.linux");

content_handlers.set("application/pdf", content_handler_save);

external_content_handlers.set("image/*", "xdg-open");
external_content_handlers.set("video/*", "xdg-open");
external_content_handlers.set("audio/*", "xdg-open");
external_content_handlers.set("application/pdf", "xdg-open");
external_content_handlers.set("application/postscript", "xdg-open");
external_content_handlers.set("application/x-dvi", "xdg-open");

// Time-stamp: "2019-01-27 00:55:30 phil"

dumpln("50os.linux");

content_handlers.set("application/pdf", content_handler_save);

external_content_handlers.set("image/*", "xdg-open");
external_content_handlers.set("video/*", "yd2tv");
external_content_handlers.set("audio/*", "yd2tv");
external_content_handlers.set("application/octet-stream", "yd2tv");
external_content_handlers.set("application/pdf", "xdg-open");
external_content_handlers.set("application/postscript", "xdg-open");
external_content_handlers.set("application/x-dvi", "xdg-open");

Set up handlers for shell-command-on-url.


#!/usr/bin/env node

var sc = require('skale-engine').context();

var file = process.argv[2] || '/etc/hosts';

sc.textFile(file)
  .flatMap(line => line.split(' '))
  .map(word => [word, 1])
  .reduceByKey((a, b) => a + b, 0)
  .count().then(console.log)

#!/usr/bin/env node

var sc = require('skale-engine').context();

var file = process.argv[2] || '/etc/hosts';

sc.textFile(file)
  .flatMap(line => line.split(' '))
  .map(word => [word, 1])
  .reduceByKey((a, b) => a + b, 0)
  .count().then(function (res) {
  	console.log(res);
	sc.end();
  });

Add sc.end() to exit after results. Suggested by @tfauck.


const DEFAULT_STATE = {
  searchTerm: ''
}

const rootReducer = (state = DEFAULT_STATE, action) => {
  switch (action.type) {

  }
}

export default rootReducer

const DEFAULT_STATE = {
  searchTerm: ''
}

const rootReducer = (state = DEFAULT_STATE, action) => {
  switch (action.type) {
    default:
      return state
  }
}

export default rootReducer

Add default case for switch statement


var stringUtil  = require('ember-cli-string-utils');
var SilentError = require('silent-error');
var pathUtil    = require('ember-cli-path-utils');

module.exports = {
  description: 'Generates an ember-data adapter.',

  availableOptions: [
    { name: 'base-class', type: String }
  ],

  locals: function(options) {
    var adapterName     = options.entity.name;
    var baseClass       = 'JSONAPIAdapter';
    var importStatement = 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';';
    var isAddon         = options.inRepoAddon || options.project.isEmberCLIAddon();
    var relativePath    = pathUtil.getRelativePath(options.entity.name);

    if (options.pod && options.podPath) {
        relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name);
    }

    if (!isAddon && !options.baseClass && adapterName !== 'application') {
      options.baseClass = 'application';
    }

    if (options.baseClass === adapterName) {
      throw new SilentError('Adapters cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.');
    }

    if (options.baseClass) {
      baseClass = stringUtil.classify(options.baseClass.replace('\/', '-'));
      baseClass = baseClass + 'Adapter';
      importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';';
    }

    return {
      importStatement: importStatement,
      baseClass: baseClass
    };
  }
};

var stringUtil  = require('ember-cli-string-utils');
var SilentError = require('silent-error');
var pathUtil    = require('ember-cli-path-utils');

module.exports = {
  description: 'Generates an ember-data adapter.',

  availableOptions: [
    { name: 'base-class', type: String }
  ],

  locals: function(options) {
    var adapterName     = options.entity.name;
    var baseClass       = 'JSONAPIAdapter';
    var importStatement = 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';';
    var isAddon         = options.inRepoAddon || options.project.isEmberCLIAddon();
    var relativePath    = pathUtil.getRelativePath(options.entity.name);

    if (options.pod && options.podPath) {
        relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name);
    }

    if (!isAddon && !options.baseClass && adapterName !== 'application') {
      options.baseClass = 'application';
    }

    if (options.baseClass === adapterName) {
      throw new SilentError('Adapters cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.');
    }

    if (options.baseClass) {
      baseClass = stringUtil.classify(options.baseClass.replace('/', '-'));
      baseClass = baseClass + 'Adapter';
      importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';';
    }

    return {
      importStatement: importStatement,
      baseClass: baseClass
    };
  }
};

Fix linting issue after updating mocha-eslint.


jQuery(document).ready(function() {

    jQuery('.kitabu-datetime-field').datetimepicker();
})

jQuery(document).ready(function() {

    $('.kitabu-datetime-field').datetimepicker();
})

Make jquery datetimepicker work on my computer:)


define(['jquery', 'underscore', 'backbone', 'model_want', 'utils'], function($, _, Backbone, Models, Utils) {
	Models.Wants = Backbone.Collection.extend({
		model: Models.Want,
		initialize: function() {
			this.fetch({
				dataType: 'json',
				success: function(model, response, options) {

				},
				error: function(model, response, options) {
					if (response.status === 403) {
						Utils.logIn();
					}
				}
			});
		},
		parse: function(response) {
			return response.listings;
		}
	});
	return Models;
});

define(['jquery', 'underscore', 'backbone', 'model_want', 'utils'], function($, _, Backbone, Models, Utils) {
	Models.Wants = Backbone.Collection.extend({
		model: Models.Want,
		initialize: function() {
			this.fetch({
				dataType: 'json',
				success: function(model, response, options) {

				},
				error: function(model, response, options) {
					if (response.status === 403) {
						Utils.logIn();
					}
				}
			});
		},
		parse: function(response) {
			return response.listings;
		},

		comparator: function(first, second) {
			var dateValue1 = first.get("date_start");
			var dateValue2 = second.get("date_start");

			var firstDate = Date.parse(dateValue1);
			var secondDate = Date.parse(dateValue2);

			var difference = secondDate - firstDate;
			if (difference > 0) {
				return 1;
			} else if (difference == 0) {
				return 0;
			} else {
				return -1;
			}
		}
	});
	return Models;
});

Add comparator to sort listings in reverse chronological order.


var app = app || {};

(function () {
    'use strict';

    app.controller = function() {

        this.list = new app.TodoList(); // Todo collection
        this.title = m.prop('');        // Temp title placeholder
        this.filter = m.prop(m.route.param('filter') || '');       // TodoList filter

        // Add a Todo
        this.add = function(title) {
            if(this.title()) {
                this.list.push(new app.Todo({title: title()}));
                this.title('');
            }
        };

        //check whether a todo is visible
        this.isVisible = function(todo) {
            if(this.filter() == '')
                return true;
            if (this.filter() == 'active')
                return !todo.completed();
            if (this.filter() == 'completed')
                return todo.completed();
        }

        this.clearTitle = function() {
            this.title('')
        }

        // Removing a Todo from the list
        this.remove = function(key) {
            this.list.splice(key, 1)
        }

        // Remove all Todos where Completed == true
        this.clearCompleted = function() {
            for(var i = 0; i < this.list.length; i++) {
                if(this.list[i].completed())
                    this.list.splice(i, 1)
            }
        }

        // Total amount of Todos completed
        this.amountCompleted = function() {
            var amount = 0;

            for(var i = 0; i < this.list.length; i++)
                if(this.list[i].completed())
                    amount++;

            return amount;
        }
    };

})();

var app = app || {};

(function () {
    'use strict';

    app.controller = function() {

        this.list = new app.TodoList(); // Todo collection
        this.title = m.prop('');        // Temp title placeholder
        this.filter = m.prop(m.route.param('filter') || '');       // TodoList filter

        // Add a Todo
        this.add = function(title) {
            if(this.title()) {
                this.list.push(new app.Todo({title: title()}));
                this.title('');
            }
        };

        //check whether a todo is visible
        this.isVisible = function(todo) {
            if(this.filter() == '')
                return true;
            if (this.filter() == 'active')
                return !todo.completed();
            if (this.filter() == 'completed')
                return todo.completed();
        }

        this.clearTitle = function() {
            this.title('')
        }

        // Removing a Todo from the list
        this.remove = function(key) {
            this.list.splice(key, 1)
        }

        // Remove all Todos where Completed == true
        this.clearCompleted = function() {
            for(var i = this.list.length - 1; i >= 0; i--) {
                if (this.list[i].completed()) {
                    this.list.splice(i, 1);
                }
            }
        }

        // Total amount of Todos completed
        this.amountCompleted = function() {
            var amount = 0;

            for(var i = 0; i < this.list.length; i++)
                if(this.list[i].completed())
                    amount++;

            return amount;
        }
    };

})();

Fix "clear completed" button to actually work


import delegate from 'delegate';
import {stageChangeToAnnotation, isEditable, editAnnotationHandle, setFocus, stagePreviousContent} from 'lib/ui/content/annotations';

delegate(document, '.annotate.note', 'click', e => {
  let annotationId = e.target.dataset.annotationId;

  document.querySelector(`.annotate.note-content-wrapper[data-annotation-id="${annotationId}"]`)
  .classList.toggle('revealed');
});

// Stage content for cancel to work and override the default select action which would keep the `create-menu` open
delegate(document, '.note-content', 'click', e => {
  handleNoteContentPressed(e)
});

delegate(document, '.note-icon', 'click', e => {
  let annotationId = e.delegateTarget.dataset.annotationId;

  document.querySelector(`.annotate.note-content-wrapper[data-annotation-id="${annotationId}"]`)
  .classList.toggle('revealed');
});

delegate(document, '.note-content', 'input', e => {
  stageChangeToAnnotation(e.target.parentElement.previousElementSibling, {content: e.target.innerText});
});

function handleNoteContentPressed(e){
  if (isEditable()) {
    editAnnotationHandle(e.target.parentElement.previousElementSibling);
    stagePreviousContent(e.target.innerText);
    setFocus(e.target);
  }
}

Revert "Add newline to end of file."


import { applyMiddleware, compose, createStore } from 'redux'
import { createHistory } from 'history'
import { syncHistory } from 'react-router-redux'
import thunk from 'redux-thunk'

import devToolsExtension from './devToolsExtension'
import reducer from 'reducers'

export const history = createHistory()

const reduxRouterMiddleware = syncHistory(history)

const store = createStore(reducer,
  compose(
    applyMiddleware(thunk, reduxRouterMiddleware),
    devToolsExtension
  )
)

if (module.hot) {
  module.hot.accept('../reducers', () => {
    const nextReducer =
      require('../reducers').default // eslint-disable-line global-require

    store.replaceReducer(nextReducer)
  })
}

reduxRouterMiddleware.listenForReplays(store)

export default store

import { applyMiddleware, compose, createStore } from 'redux'
import { createHistory } from 'history'
import { syncHistory } from 'react-router-redux'
import { apiMiddleware } from 'redux-api-middleware'
import thunk from 'redux-thunk'

import devToolsExtension from './devToolsExtension'
import reducer from 'reducers'

export const history = createHistory()

const reduxRouterMiddleware = syncHistory(history)

const store = createStore(reducer,
  compose(
    applyMiddleware(thunk, reduxRouterMiddleware, apiMiddleware),
    devToolsExtension
  )
)

if (module.hot) {
  module.hot.accept('../reducers', () => {
    const nextReducer =
      require('../reducers').default // eslint-disable-line global-require

    store.replaceReducer(nextReducer)
  })
}

reduxRouterMiddleware.listenForReplays(store)

export default store

Include API middleware in the store


#!/usr/bin/env node

console.error("The CLI has been moved into the package `babel-cli`. See http://babeljs.io/docs/usage/cli/");
process.exit(1);

#!/usr/bin/env node

console.error("You have mistakenly installed the `babel` package, which is a no-op in Babel 6.\n" +
  "Babel's CLI commands have been moved from the `babel` package to the `babel-cli` package.\n" +
  "\n" +
  "    npm uninstall babel\n" +
  "    npm install babel-cli\n" +
  "\n" +
  "See http://babeljs.io/docs/usage/cli/ for setup instructions.");
process.exit(1);

Improve the error messaging for using the wrong CLI script.


// Globals
var angular = angular;
var nOrg = nOrg;
angular.module('nOrg', ['ui.bootstrap', 'ui.keypress'])

  .controller('NOrgCtrl', function NOrgCtrl($scope, $http, $log) {
    $scope.controlName = 'NOrgCtrl';

    $scope.keydown = {
      'tab': 'node.toggle($event)',
      72: 'node.toggleHeaders($event)', // h

      'down': 'node.cursorDown($event)',
      'up': 'node.cursorUp($event)',
      'right': 'node.cursorRight($event)',
      'left': 'node.cursorLeft($event)'
    };
    $scope.keydown_aliases = {
      74: 'down',               // j
      75: 'up',                 // k
      87: 'up',                 // w
      83: 'down',               // s
      65: 'left',               // a
      68: 'right'               // d
    };
    for (var alias in $scope.keydown_aliases) {
      $scope.keydown[alias] = $scope.keydown[$scope.keydown_aliases[alias]];
    }

    $http.get('app/nodes.json').success(function loadNode(node) {
      // Load the initial nodes JSON
      $scope.node = nOrg.newRoot(node);
    });
  })

  .directive('norgCursor', function norgCursor() {
    return function (scope, element, attrs) {
      attrs.$observe('norgCursor', function (newValue) {
        if (newValue === 'true') {
          element[0].focus();
        }
      });
    };
  });

//NOrgCtrl.$inject = ['$scope', '$http'];

// Globals
var angular = angular;
var nOrg = nOrg;
angular.module('nOrg', ['ui.bootstrap', 'ui.keypress'])

  .controller('NOrgCtrl', function NOrgCtrl($scope, $http, $log) {
    $scope.controlName = 'NOrgCtrl';

    $scope.keydown = {
      'tab': 'node.toggle($event)',
      '72': 'node.toggleHeaders($event)', // h

      'down 74 83': 'node.cursorDown($event)', // j, s
      'up 75 87': 'node.cursorUp($event)',     // k, w
      'right 68': 'node.cursorRight($event)',  // d
      'left 65': 'node.cursorLeft($event)',    // a
    };

    $http.get('app/nodes.json').success(function loadNode(node) {
      // Load the initial nodes JSON
      $scope.node = nOrg.newRoot(node);
    });
  })

  .directive('norgCursor', function norgCursor() {
    return function (scope, element, attrs) {
      attrs.$observe('norgCursor', function (newValue) {
        if (newValue === 'true') {
          element[0].focus();
        }
      });
    };
  });

//NOrgCtrl.$inject = ['$scope', '$http'];

Use angular-ui keypress handling for aliases


// ==UserScript==
// @id             iitc-plugin-drawtools-sync@hansolo669
// @name           IITC plugin: drawtools sync
// @category       Tweaks
// @version        0.1.0
// @namespace      https://github.com/hansolo669/iitc-tweaks
// @updateURL      https://iitc.reallyawesomedomain.com/drawtools-sync.meta.js
// @downloadURL    https://iitc.reallyawesomedomain.com/drawtools-sync.user.js
// @description    Uses the 'sync' plugin to sync drawtools data via the google realtime API.
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @include        https://www.ingress.com/mission/*
// @include        http://www.ingress.com/mission/*
// @match          https://www.ingress.com/mission/*
// @match          http://www.ingress.com/mission/*
// @grant          none
// ==/UserScript==

// ==UserScript==
// @id             iitc-plugin-drawtools-sync@hansolo669
// @name           IITC plugin: drawtools sync
// @category       Tweaks
// @version        0.1.1
// @namespace      https://github.com/hansolo669/iitc-tweaks
// @updateURL      https://iitc.reallyawesomedomain.com/drawtools-sync.meta.js
// @downloadURL    https://iitc.reallyawesomedomain.com/drawtools-sync.user.js
// @description    Uses the 'sync' plugin to sync drawtools data via the google realtime API.
// @include        https://*.ingress.com/intel*
// @include        http://*.ingress.com/intel*
// @match          https://*.ingress.com/intel*
// @match          http://*.ingress.com/intel*
// @include        https://*.ingress.com/mission/*
// @include        http://*.ingress.com/mission/*
// @match          https://*.ingress.com/mission/*
// @match          http://*.ingress.com/mission/*
// @grant          none
// ==/UserScript==

Fix for intel routing changes


function contains(list, elem) {
    return list.indexOf(elem) !== -1;
}

module.exports = {
    contains: contains
}

function fastContains(list, elem) {
    return list.indexOf(elem) !== -1;
}

function slowContains(list, elem) {
    for (var i = 0; i < list.length; i++) {
        if (list[i] === elem) {
            return true;
        }
    }
    return false;
}

var contains = Array.prototype.indexOf ? fastContains : slowContains;

module.exports = {
    contains: contains
}

Make contains() actually work in IE8


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

export default class Footer extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {

    return (

 Copyright © woolfey.com

About

Careers

    )
  }
}

Add link to about me section


var _global = (function() { return this; })();
var NativeWebSocket = _global.WebSocket || _global.MozWebSocket;
var websocket_version = require('./version');

/**
 * Expose a W3C WebSocket class with just one or two arguments.
 */
function W3CWebSocket(uri, protocols) {
	var native_instance;

	if (protocols) {
		native_instance = new NativeWebSocket(uri, protocols);
	}
	else {
		native_instance = new NativeWebSocket(uri);
	}

	/**
	 * 'native_instance' is an instance of nativeWebSocket (the browser's WebSocket
	 * class). Since it is an Object it will be returned as it is when creating an
	 * instance of W3CWebSocket via 'new W3CWebSocket()'.
	 *
	 * ECMAScript 5: http://bclary.com/2004/11/07/#a-13.2.2
	 */
	return native_instance;
}
if (NativeWebSocket) {
	['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'].forEach(function(prop) {
		Object.defineProperty(W3CWebSocket, prop, {
			get: function() { return NativeWebSocket[prop]; }
		});
	});
}

/**
 * Module exports.
 */
module.exports = {
    'w3cwebsocket' : NativeWebSocket ? W3CWebSocket : null,
    'version'      : websocket_version
};

var _global = (function () {
	if (!this && typeof global !== 'undefined') {
		return global;
	}
	return this;
})();
var NativeWebSocket = _global.WebSocket || _global.MozWebSocket;
var websocket_version = require('./version');

/**
 * Expose a W3C WebSocket class with just one or two arguments.
 */
function W3CWebSocket(uri, protocols) {
	var native_instance;

	if (protocols) {
		native_instance = new NativeWebSocket(uri, protocols);
	}
	else {
		native_instance = new NativeWebSocket(uri);
	}

	/**
	 * 'native_instance' is an instance of nativeWebSocket (the browser's WebSocket
	 * class). Since it is an Object it will be returned as it is when creating an
	 * instance of W3CWebSocket via 'new W3CWebSocket()'.
	 *
	 * ECMAScript 5: http://bclary.com/2004/11/07/#a-13.2.2
	 */
	return native_instance;
}
if (NativeWebSocket) {
	['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'].forEach(function(prop) {
		Object.defineProperty(W3CWebSocket, prop, {
			get: function() { return NativeWebSocket[prop]; }
		});
	});
}

/**
 * Module exports.
 */
module.exports = {
    'w3cwebsocket' : NativeWebSocket ? W3CWebSocket : null,
    'version'      : websocket_version
};

Fix Webpack global scope issue


var request = require('superagent');
var secrets = require('./load-secrets')('../client_secrets');
var serverBaseUri = secrets.v1ServerBaseUri;
var debug = require('debug')('query-v1');

function v1Query(query) {
  return request
    .get(serverBaseUri + '/query.v1')
    .set('Authorization', 'Bearer ' + secrets.v1AccessToken)
    .send(query)
}

module.exports = v1Query;

var request = require('superagent');
var secrets = require('./load-secrets')('../client_secrets');
var serverBaseUri = secrets.v1ServerBaseUri;
var debug = require('debug')('query-v1');

function v1Query(query) {
  return request
    .post(serverBaseUri + '/query.v1')
    .set('Authorization', 'Bearer ' + secrets.v1AccessToken)
    .send(query)
}

module.exports = v1Query;

Use post verb instead of get for querying V1


var app = require('express').Router();

process.env.NTB_API_USERAGENT = 'Hytteadmin/' + require('../package.json');
var turbasen = require('turbasen-auth');

app.get('/', function(req, res) {
  if (req.session && req.session.user) {
    res.json(req.session.user);
  } else {
    res.status(401);
    res.json({authenticated: false});
  }
});

app.get('/login/sherpa/signon', function(req, res) {
  throw new Error('Not Implemented');
});

app.get('/login/sherpa/callback', function(req, res) {
  throw new Error('Not Implemented');
});

app.post('/login/turbasen', turbasen.middleware, function(req, res) {
  if (req.turbasenAuth) {
    req.session.user = req.turbasenAuth;
    res.status(200);
    res.json(req.session.user);
  } else {
    req.session.destroy(function(err) {
      if (err) { throw err; }

      res.status(401);
      res.json({message: 'Invalid email or password'});
    });
  }
});

app.post('/logout', function(req, res) {
  req.session.destroy(function(err) {
    if (err) { throw err; }

    res.status(204).end();
  });
});

module.exports = app;

var app = require('express').Router();

process.env.NTB_USER_AGENT = 'Hytteadmin/' + require('../package.json');
var turbasen = require('turbasen-auth');

app.get('/', function(req, res) {
  if (req.session && req.session.user) {
    res.json(req.session.user);
  } else {
    res.status(401);
    res.json({authenticated: false});
  }
});

app.get('/login/sherpa/signon', function(req, res) {
  throw new Error('Not Implemented');
});

app.get('/login/sherpa/callback', function(req, res) {
  throw new Error('Not Implemented');
});

app.post('/login/turbasen', turbasen.middleware, function(req, res) {
  if (req.turbasenAuth) {
    req.session.user = req.turbasenAuth;
    res.status(200);
    res.json(req.session.user);
  } else {
    req.session.destroy(function(err) {
      if (err) { throw err; }

      res.status(401);
      res.json({message: 'Invalid email or password'});
    });
  }
});

app.post('/logout', function(req, res) {
  req.session.destroy(function(err) {
    if (err) { throw err; }

    res.status(204).end();
  });
});

module.exports = app;

Set correct Turbasen User Agent env var


// Problem: Check whether a given year is a leap year or not.

// Input: A year
// Output: A boolean value of whether the year is a leap year or not

// Pseudocode
// Create a function that takes a year as a parameter
// Make an conditional statement:
// --> 1st check use an 'or' statement to see if year is not divisible by four or evenly divided by 100 and return that it is not a leap year
// --> 2nd make an else if statement using another 'or' operator that checks if year is evenly divisible four using modulus or if the year is evenly divided by 400

// Long Way
// var leapYear = function(year) {
//   var leap = false;
//   if(year % 400 === 0){
//     //console.log("Yes, this is a leap year!");
//     leap = true;
//     //return leap
//   }else if(year % 100 === 0){
//     leap = false
//   }else if(year % 4 === 0){
//     leap = true
//   }else if(year % 4 !== 0 ){
//     leap = false
//   };
//   if(leap === true){
//     console.log("LEAP YEAR")
//     return leap
//   }else{
//     console.log("not leap year")
//     return leap
//   };
// };

// Refactored Way
var leapYear = function(year) {
  var leap = false;
  if(year % 400 === 0 || year % 4 === 0){
    console.log("Yes, this is a leap year!");
    leap = true;
    return leap
  }else if(year % 4 !== 0 || year % 100 === 0){
    console.log("No, this is not a leap year")
    return leap
  };
};

//console.log(leapYear(1999))
//console.log(leapYear(2000))
console.log(leapYear(1900))
//console.log(leapYear(1200))
//console.log(leapYear(1493))
//console.log(leapYear(1776))

Complete long form solution, refactored solution still in works


let moment = require('moment');

let JobRun = require('../JobRun');
let JobTaskList = require('../JobTaskList');

describe('JobRun', function () {

  describe('#getDateCreated', function () {

    it('should return null if createdAt is undefined', function () {
      let activeRun = new JobRun({foo: 'bar'});
      expect(activeRun.getDateCreated()).toEqual(null);
    });

    it('should return the correct value in milliseconds', function () {
      let activeRun = new JobRun({createdAt: '1990-01-03T02:00:00Z-1'});
      expect(activeRun.getDateCreated()).toEqual(631332000000);
    });

  });

  describe('#getJobID', function () {

    it('should return the jobId', function () {
      let activeRun = new JobRun({jobId: 'foo'});
      expect(activeRun.getJobID()).toEqual('foo');
    });

  });

  describe('#getStatus', function () {

    it('should return the id', function () {
      let activeRun = new JobRun({status: 'foo'});
      expect(activeRun.getStatus()).toEqual('foo');
    });

  });

  describe('#getTasks', function () {

    it('should return an instance of JobTaskList', function () {
      let activeRun = new JobRun({id: 'foo', tasks: []});
      expect(activeRun.getTasks() instanceof JobTaskList).toBeTruthy();
    });

  });

});

Remove unused moment lib form job run test


module.exports = [
      {
        "direct": "https://d24kjznqej0s8a.cloudfront.net/2016/encryption_campaign/moz.final.3.emailpartner_1",
        "social": "https://d24kjznqej0s8a.cloudfront.net/2016/encryption_campaign/moz.final.2.social_3",
        "title": "Privacy Lets You Be You",
        "description": "Privacy depends on encryption. Learn more about how it works, why it's essential, and why it's worth protecting.",
        "date": "February 08, 2016",
        "duration": "0:58",
        "poster": "/assets/encrypt-poster-dark-1920x1080.jpg",
        "thumbnail": "/assets/thumbnail-beat1.jpg"
      },{
        "direct": "http://grochtdreis.de/fuer-jsfiddle/video/sintel_trailer-480",
        "social": "http://grochtdreis.de/fuer-jsfiddle/video/sintel_trailer-480",
        "title": "Meet Encryption",
        "description": "Description of the second video",
        "date": "February 24, 2016",
        "duration": "0:58",
        "poster": "/assets/video2poster.jpg",
        "thumbnail": "/assets/thumbnail-beat2.jpg"
      }
     ]

module.exports = [
      {
        "direct": "https://d24kjznqej0s8a.cloudfront.net/2016/encryption_campaign/moz.final.3.emailpartner_1",
        "social": "https://d24kjznqej0s8a.cloudfront.net/2016/encryption_campaign/moz.final.2.social_3",
        "title": "Privacy Lets You Be You",
        "description": "Privacy depends on encryption. Learn more about how it works, why it's essential, and why it's worth protecting.",
        "date": "February 08, 2016",
        "duration": "0:58",
        "poster": "/assets/encrypt-poster-dark-1920x1080.jpg",
        "thumbnail": "/assets/thumbnail-beat1.jpg"
      },{
        "direct": "https://d24kjznqej0s8a.cloudfront.net/2016/encryption_campaign/Mozilla_Encrypt_Beat2_landingpage",
        "social": "https://d24kjznqej0s8a.cloudfront.net/2016/encryption_campaign/Mozilla_Encrypt_Beat2_landingpage",
        "title": "Meet Encryption",
        "description": "Meet Encryption, and learn how she's hard at work to keep you safe online.",
        "date": "February 24, 2016",
        "duration": "1:16",
        "poster": "/assets/video2poster.jpg",
        "thumbnail": "/assets/thumbnail-beat2.jpg"
      }
     ]

Add beat 2 video and description


import ReactDOM from 'react-dom';
import React from 'react';
import {build as fetchBuild, buildLog as fetchBuildLog,cancelBuild as cancelBuildApi} from './../api/Api.jsx';
import Build from './../components/job/build/Build.jsx';
import Drawer from './../Drawer.jsx';
import page from 'page';

function dataChange(build){
  ReactDOM.render(<Build build={build} subBuild={build.subBuild}/>, document.getElementById('content'));
  ReactDOM.render(<Drawer menu="build" build={build}/>, document.getElementById('nav'));
}
async function buildChange(build){
  const actions = build.actions;
  let query = build.query;
  const data =await fetchBuild(build.number);
  actions.BuildInfoChange(data);
  const logText = await fetchBuildLog(build.number,build.subBuild)
  actions.LogChange(logText);
}
async function cancelBuild(build){
  await  cancelBuildApi(build.cancelUrl);
}
function lineSelect(build){
  window.location.hash =build.selectedLine;
}

export default function(build){
  const actions = build.actions;
  actions.BuildInfoChange.onAction = dataChange;
  actions.LogChange.onAction = dataChange;
  actions.CancelBuild.onAction = cancelBuild;
  actions.BuildChange.onAction = buildChange;
  actions.LineSelect.onAction = lineSelect;
}

import ReactDOM from 'react-dom';
import React from 'react';
import {build as fetchBuild, buildLog as fetchBuildLog,cancelBuild as cancelBuildApi} from './../api/Api.jsx';
import BuildPage from './../pages/BuildPage.jsx';
import Drawer from './../Drawer.jsx';
import page from 'page';
import autoRefreshComponent from './../components/lib/AutoRefreshComponent.js';

function dataChange(build){
  const buildPage =<BuildPage build={build} subBuild={build.subBuild}/>
  if(build.inProgress){
    const AutoRefreshBuildPage = autoRefreshComponent(buildPage,()=>{
      build.actions.BuildChange({buildNumber:build.number,subBuild:build.subBuild});
    });
    ReactDOM.render(<AutoRefreshBuildPage/>, document.getElementById('content'));
  }else{
    ReactDOM.render(buildPage, document.getElementById('content'));
  }
  ReactDOM.render(<Drawer menu="build" build={build}/>, document.getElementById('nav'));
}
async function buildChange(build){
  const actions = build.actions;
  let query = build.query;
  const data =await fetchBuild(build.number);
  actions.BuildInfoChange(data);
  const logText = await fetchBuildLog(build.number,build.subBuild)
  actions.LogChange(logText);
}
async function cancelBuild(build){
  await  cancelBuildApi(build.cancelUrl);
}
function lineSelect(build){
  window.location.hash =build.selectedLine;
}

export default function(build){
  const actions = build.actions;
  actions.BuildInfoChange.onAction = dataChange;
  actions.LogChange.onAction = dataChange;
  actions.CancelBuild.onAction = cancelBuild;
  actions.BuildChange.onAction = buildChange;
  actions.LineSelect.onAction = lineSelect;
}

Build page refresh if in progress


const path = require('path');
const apiSpecAliases = require('../frontend_build/src/apiSpecExportTools').coreAliases();

const moduleNameMapper = {
  '^testUtils$': path.resolve(__dirname, './testUtils'),
};

Object.keys(apiSpecAliases).forEach(key => {
  moduleNameMapper['^' + key.replace(/\./g, '\\.') + '$'] = apiSpecAliases[key];
});

module.exports = {
  globals: {
    __kolibriModuleName: 'testmodule',
    __version: 'testversion',
    __events: {},
    __once: {},
  },
  rootDir: path.resolve(__dirname, '../'),
  moduleFileExtensions: ['js', 'json', 'vue'],
  moduleNameMapper,
  testURL: 'http://kolibri.time',
  transform: {
    '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
    '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
  },
  transformIgnorePatterns: ['/node_modules/(?!(keen-ui)/).*/'],
  snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
  setupFiles: [path.resolve(__dirname, './setup')],
  coverageDirectory: '<rootDir>/coverage',
  collectCoverageFrom: [
    'kolibri/**/assets/src/**/*.{js,vue}',
    '!**/node_modules/**',
    'kolibri/**/**/assets/src/**/*.{js,vue}',
  ],
};

const path = require('path');
const apiSpecAliases = require('../frontend_build/src/apiSpecExportTools').coreAliases();

const moduleNameMapper = {
  '^testUtils$': path.resolve(__dirname, './testUtils'),
};

Object.keys(apiSpecAliases).forEach(key => {
  moduleNameMapper['^' + key.replace(/\./g, '\\.') + '$'] = apiSpecAliases[key];
});

module.exports = {
  globals: {
    __kolibriModuleName: 'testmodule',
    __version: 'testversion',
    __events: {},
    __once: {},
  },
  rootDir: path.resolve(__dirname, '../'),
  moduleFileExtensions: ['js', 'json', 'vue'],
  moduleNameMapper,
  testURL: 'http://kolibri.time',
  transform: {
    '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
    '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
  },
  transformIgnorePatterns: ['/node_modules/(?!(keen-ui)/).*/'],
  snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
  setupFiles: [path.resolve(__dirname, './setup')],
  coverageDirectory: '<rootDir>/coverage',
  collectCoverageFrom: [
    'frontend_build/src/*.js',
    'kolibri/**/assets/src/**/*.{js,vue}',
    '!**/node_modules/**',
    'kolibri/**/**/assets/src/**/*.{js,vue}',
  ],
};

Add frontend_build to coverage report


#!/usr/bin/env node

/**
 * Jit hash-object
 */
var program = require('commander'),
    Blob = require('./common/blob');

program
  // TODO
  .option('-t <type>', 'object type')
  // TODO
  .option('-w', 'write the object into the object database')
  // TODO
  .option('--stdin', 'read the object from stdin')
  // TODO
  .option('--stdin-paths', 'read file names from stdin')
  // TODO
  .option('--no-filters store file as is without filters')
  // TODO
  .option('--path <file>', 'process file as it were from this path')
  .parse(process.argv);

content = '';

if(program.stdin) {
  process.stdin.on('data', function(chunk) {
    content += chunk;
  })
  process.stdin.on('end', function() {
    run();
  })
} else {
  run();
}

function run() {
  Blob.hash_object({content: content}, function(err, blob) {
    console.log(blob)
  });
}

#!/usr/bin/env node

/**
 * Jit hash-object
 */
var program = require('commander'),
    fs = require('fs'),
    path = require('path'),
    Blob = require('./common/blob');

program
  // TODO
  .option('-t <type>', 'object type')
  // TODO
  .option('-w', 'write the object into the object database')
  .option('--stdin', 'read the object from stdin')
  // TODO
  .option('--stdin-paths', 'read file names from stdin')
  // TODO
  .option('--no-filters store file as is without filters')
  // TODO
  .option('--path <file>', 'process file as it were from this path')
  .parse(process.argv);

content = '';

if(program.stdin) {
  process.stdin.on('data', function(chunk) {
    content += chunk;
  })
  process.stdin.on('end', function() {
    run();
  })
} else if(program.args.length > 0) {
  var file_path = path.resolve(program.args[0]);
  fs.readFile(file_path, 'utf8', function(err, data) {
    content = data;
    run();
  });
}
else {
  run();
}

function run() {
  var blob = new Blob();
  blob.hash_object({content: content}, function(err) {
    // console.log(blob);
  });
}

Allow filling content of a blob from file path


import React, { Component } from 'react'
import PropTypes from 'prop-types'

import { connect } from 'react-redux'
import { Link, Router } from 'react-router-dom'

import { fetchSmifDetails } from '../actions/actions.js'

class Footer extends Component {

    constructor(props) {
        super(props)

    }

    componentDidMount() {
        const { dispatch } = this.props
        dispatch(fetchSmifDetails())
    }

    renderLoading() {
        return (

                Loading...

        )
    }

    renderError() {
        return (

                Error

        )
    }

    renderFooter(version) {
        return (

                        {version}

        )
    }

    render() {
        const {isFetching, smif} = this.props

        if (isFetching) {
            return this.renderLoading()
        } else {
            return this.renderFooter(smif.version)
        }
    }
}

Footer.propTypes = {
    smif: PropTypes.object.isRequired
}

function mapStateToProps(state) {
    const { smif } = state

    return {
        smif: state.smif.item,
        isFetching: (state.smif.isFetching)
    }
}

export default connect(mapStateToProps)(Footer)

import React, { Component } from 'react'
import PropTypes from 'prop-types'

import { connect } from 'react-redux'
import { Link, Router } from 'react-router-dom'

import { fetchSmifDetails } from '../actions/actions.js'

class Footer extends Component {

    constructor(props) {
        super(props)

    }

    componentDidMount() {
        const { dispatch } = this.props
        dispatch(fetchSmifDetails())
    }

    renderLoading() {
        return (

                Loading...

        )
    }

    renderError() {
        return (

                Error

        )
    }

    renderFooter(version) {
        return (

                        smif version: {version}

        )
    }

    render() {
        const {isFetching, smif} = this.props

        if (isFetching) {
            return this.renderLoading()
        } else {
            return this.renderFooter(smif.version)
        }
    }
}

Footer.propTypes = {
    smif: PropTypes.object.isRequired
}

function mapStateToProps(state) {
    const { smif } = state

    return {
        smif: state.smif.item,
        isFetching: (state.smif.isFetching)
    }
}

export default connect(mapStateToProps)(Footer)

Add 'smif version' to label


let express = require('express')
let bodyParser = require('body-parser')
let request = require('request')

let remote = process.argv[2]
let app = express()
app.use(bodyParser.json())

let proxyResponse = (res) => {
  return (err, upstream) => {
    if(err) { res.status(500); console.error(err); return }
    res.send(upstream.body)
  }
}

let proxyGet = (endpoint) => {
  app.get(endpoint, (req, res) => {
    let url = `${remote}${endpoint}`
    request.get(url, {json: true}, proxyResponse(res))
  })
}

let proxyPost = (endpoint) => {
  app.post(endpoint, (req, res) => {
    let url = `${remote}${endpoint}`
    request.post(url, {json: true, body: req.body}, proxyResponse(res))
  })
}

proxyGet('/whoami')
proxyGet('/collections')
proxyPost('/search')

app.use(express.static(`${__dirname}/build`))

app.listen(+(process.env.PORT || 8000), 'localhost')

let express = require('express')
let bodyParser = require('body-parser')
let request = require('request')

let remote = process.argv[2]
let app = express()
app.use(bodyParser.json())

let proxyResponse = (res) => {
  return (err, upstream) => {
    if(err) { res.status(500); console.error(err); return }
    res.send(upstream.body)
  }
}

let proxyGet = (endpoint) => {
  app.get(endpoint, (req, res) => {
    let url = `${remote}${req.originalUrl}`
    request.get(url, {json: true}, proxyResponse(res))
  })
}

let proxyPost = (endpoint) => {
  app.post(endpoint, (req, res) => {
    let url = `${remote}${endpoint}`
    request.post(url, {json: true, body: req.body}, proxyResponse(res))
  })
}

proxyGet('/whoami')
proxyGet('/collections')
proxyPost('/search')
proxyGet('/doc/\*')

app.use(express.static(`${__dirname}/build`))

app.listen(+(process.env.PORT || 8000), 'localhost')

Add proxyGet for /doc urls.


/* eslint-env node */
'use strict';

module.exports = function(environment) {
  let ENV = {
    modulePrefix: 'labs-community-portal',
    environment,
    rootURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      },
      EXTEND_PROTOTYPES: {
        // Prevent Ember Data from overriding Date.parse.
        Date: false
      }
    },

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

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

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

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

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

  if (environment === 'production') {

  }

  return ENV;
};

/* eslint-env node */
'use strict';

module.exports = function(environment) {
  let ENV = {
    modulePrefix: 'labs-community-portal',
    environment,
    rootURL: '/',
    locationType: 'auto',
    'ember-cli-string-helpers': {
      only: ['dasherize']
    },
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      },
      EXTEND_PROTOTYPES: {
        // Prevent Ember Data from overriding Date.parse.
        Date: false
      }
    },

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

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

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

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

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

  if (environment === 'production') {

  }

  return ENV;
};

Include only necessary part of lib


'use strict';

module.exports = {
    'env': {
        'es6': true,
    },
    'ecmaFeatures': {
        'modules': true,
    },
    'rules': {
        // Require let or const instead of var
        'no-var': [2],
    },
};

'use strict';

module.exports = {
    'env': {
        'es6': true,
    },
    'ecmaFeatures': {
        'modules': true,
    },
    'rules': {
        // Require braces as-needed around arrow function bodies
        'arrow-body-style'       : [2, 'as-needed'],
        // Require parentheses around arrow function arguments as-needed
        'arrow-parens'           : [2, 'as-needed'],
        // Require space before/after arrow function’s arrow
        'arrow-spacing'          : [2],
        // Disallow use of this/super before calling super() in constructors
        'no-this-before-super'   : [2],
        // Disallow unnecessary computed property keys on objects
        'no-useless-computed-key': [2],
        // Disallow unnecessary constructors
        'no-useless-constructor' : [2],
        // Require let or const instead of var
        'no-var'                 : [2],
        // Require arrow functions as callbacks
        'prefer-arrow-callback'  : [2],
        // Require const declarations for variables that are never reassigned after declared
        'prefer-const'           : [2],
        // Require spread operators instead of .apply()
        'prefer-spread'          : [2],
        // Require template literals instead of string concatenation
        'prefer-template'        : [2],
        // Require rest parameters instead of arguments
        'prefer-rest-params'     : [2],
        // Disallow spacing between rest and spread operators and their expressions
        'rest-spread-spacing'    : [2, 'never'],
        // Disallow spacing around embedded expressions of template strings
        'template-curly-spacing' : [2, 'never'],
    },
};

Enable more core “ES6” rules


// create div
var sievehelpdiv = d3.select(".title").append("div")
	.attr("id", "sievehelpdiv")
	.classed("hidden", true);

// add div content
sievehelpdiv.append("h1").text("This is a big title!");

// hit window is the 'help' text
// set its behavior for mouseover and mouseout
d3.select(".sievehelplink")
	.on("mouseover", function() {sievehelpdiv.classed("hidden", false);})
	.on("mouseout", function() {sievehelpdiv.classed("hidden", true);});

// create div
var sievehelpdiv = d3.select(".title").append("div")
	.attr("id", "sievehelpdiv")
	.classed("hidden", true);

// add div content
sievehelpdiv.append("h1").text("How to use this tool");
sievehelpdiv.append("p").text("Select sites in the shaded area.");

// hit window is the 'help' text
// set its behavior for mouseover and mouseout
d3.select(".sievehelplink")
	.on("mouseover", function() {sievehelpdiv.classed("hidden", false);})
	.on("mouseout", function() {sievehelpdiv.classed("hidden", true);});

Add slightly more relevant content to the help div


/* SlideThis

Copyright (c) 2013 Liam Keene
Available under the MIT License
*/
(function($) {
    $.fn.slidethis = function(options) {

        // Default settings
        var settings = $.extend({
            'auto': true,       // Boolean: automatically animate slides (true)
            'pager': true,      // Boolean: show pager for slides (true)
            'speed': 500,       // Integer: time (in ms) of transition (500)
            'timeout': 5000,    // Integer: time (in ms) between transitions (5000)
            'width': 600,       // Integer: width (in px) of the slideshow (600)
            'height': 300,      // Integer: height (in px) of the slideshow (300)
        }, options);

        return this.each(function() {
            var $this = $(this);
            var $slides = $('#slideshow li');

            // Only show first image
            $slides.not(':first').hide();
        });

    };

}(jQuery));

/* SlideThis

Copyright (c) 2013 Liam Keene
Available under the MIT License
*/
(function($) {
    $.fn.slidethis = function(options) {

        // Default settings
        var settings = $.extend({
            'auto': true,       // Boolean: automatically animate slides (true)
            'pager': true,      // Boolean: show pager for slides (true)
            'speed': 500,       // Integer: time (in ms) of transition (500)
            'timeout': 5000,    // Integer: time (in ms) between transitions (5000)
            'width': 600,       // Integer: width (in px) of the slideshow (600)
            'height': 300,      // Integer: height (in px) of the slideshow (300)
        }, options);

        return this.each(function() {
            // Find some frequently used elements
            var $this = $(this);
            var $slides = $this.find('ul li');
            var $images = $this.find('img');

            // Hide slides except first
            $slides.not(':first').hide();

            // Set the dimensions of the images
            $images.width(settings.width).height(settings.height);

        });

    };

}(jQuery));

Set image sizes based on settings


define(["./frame"], function (Frame) {
    "use strict";

    var Graph = function () {
        this._nodeIds = {};
        this._nodes = [];
        this.edges = [];
    };

    Graph.prototype.addNode = function (node) {
        var id = node.getId();

        if (node.id) {
            this._nodeIds[id] = node;
        }

        this._nodes.push(node);
    };

    Graph.prototype.getNode = function (id) {
        return this._nodeIds[id];
    };

    Graph.prototype.getNodes = function () {
        return this._nodes;
    };

    Graph.prototype.addEdge = function (edge) {
        this.edges.push(edge);
    };

    Graph.prototype.renderIn = function (elem) {
        return new Frame(elem, this);
    };

    return Graph;
});

define(["./frame"], function (Frame) {
    "use strict";

    var Graph = function () {
        this._nodeIds = {};
        this._nodes = [];
        this.edges = [];
    };

    Graph.prototype.addNode = function (node) {
        var id = node.getId();

        if (id) {
            this._nodeIds[id] = node;
        }

        this._nodes.push(node);
    };

    Graph.prototype.getNode = function (id) {
        return this._nodeIds[id];
    };

    Graph.prototype.getNodes = function () {
        return this._nodes;
    };

    Graph.prototype.addEdge = function (edge) {
        this.edges.push(edge);
    };

    Graph.prototype.renderIn = function (elem) {
        return new Frame(elem, this);
    };

    return Graph;
});

Fix adding Node ID bug


var extend = require('extend');

var Plom = function(options) {
  this.options = options || {};
  this.data = this.options.data || {};
}

Plom.extend = function(object) {
  var NewPlom = function(options) {
    this.options = options || {};
    this.data = this.options.data || {};

    if(this.initialize) {
      this.initialize(options);
    }
  };

  object = object || null;

  NewPlom.prototype = extend({}, this.prototype, object);
  NewPlom.extend = this.extend.bind(this);

  return NewPlom;
};

Plom.prototype.set = function(key, val) {
  if(typeof val !== 'undefined') {
    this.data[key] = val;
    return this;
  }

  this.data = key;
  return this;
};

Plom.prototype.get = function(key) {
  if(key) {
    return this.data[key];
  }

  return this.data;
};

module.exports = Plom;

var extend = require('extend');

var Plom = function(options) {
  this.options = options || {};
  this.data = this.options.data || {};
}

Plom.extend = function(object) {
  var NewPlom = function(options) {
    this.options = options || {};
    this.data = this.options.data || {};

    if(this.initialize) {
      this.initialize(options);
    }
  };

  object = object || null;

  NewPlom.prototype = extend({}, this.prototype, object);
  NewPlom.extend = this.extend.bind(this);

  return NewPlom;
};

Plom.prototype.set = function(key, val) {
  var argsLength = Array.prototype.slice.call(arguments).length;

  if (argsLength === 2) {
    this.data[key] = val;
    return this;
  }

  this.data = key;
  return this;
};

Plom.prototype.get = function(key) {
  if(key) {
    return this.data[key];
  }

  return this.data;
};

module.exports = Plom;

Check number of arguments instead of val existence