'use strict'

const { ioc } = require('@adonisjs/fold')
const Cache = require('..')

class Redis extends Cache {
  constructor() {
    super()
    this.Redis = ioc.use('Redis')
  }

  /**
   * Generate cache.
   * @param {String} key
   * @param {Mixed} value
   * @param {Integer} milliseconds
   *
   * @return {TimeoutPointer}
   */
  put(key, value, milliseconds) {
    this.Redis.set(key, value, 'px', milliseconds)
  }

  /**
   * Get stored data by key.
   * @param {String} key
   *
   * @return {Mixed}
   */
  get(key) {
    return this.Redis.get(key)
  }

  /**
   * Increment stored value by one.
   * @param {String} key
   *
   * @return {Cache}
   */
  increment(key) {
    this.Redis.incr(key)
    return this
  }

  /**
   * Increment expiration of stored data by number of seconds.
   * @param {String} key
   * @param {Integer} seconds
   *
   * @return {Cache}
   */
  incrementExpiration(key, seconds) {
    this.Redis.expire(key, seconds)
    return this
  }
}

module.exports = Redis

'use strict'

const Cache = require('..')

class Redis extends Cache {
  /**
   * Namespaces to inject by IoC container.
   *
   * @attribute inject
   * @return {Array}
   */
  static get inject() {
    return ['Adonis/Src/Config', 'Adonis/Addons/Redis'];
  }

  constructor(Config, Redis) {
    super()

    const config = Config.merge('throttle.redis', {
      port: 6379,
      host: '127.0.0.1'
    })

    this.redis = Redis.namedConnection('__adonis__throttle', config)
  }

  /**
   * Generate cache.
   * @param {String} key
   * @param {Mixed} value
   * @param {Integer} milliseconds
   *
   * @return {TimeoutPointer}
   */
  put(key, value, milliseconds) {
    this.redis.set(key, value, 'px', milliseconds)
  }

  /**
   * Get stored data by key.
   * @param {String} key
   *
   * @return {Mixed}
   */
  get(key) {
    return this.redis.get(key)
  }

  /**
   * Increment stored value by one.
   * @param {String} key
   *
   * @return {Cache}
   */
  increment(key) {
    this.redis.incr(key)
    return this
  }

  /**
   * Increment expiration of stored data by number of seconds.
   * @param {String} key
   * @param {Integer} seconds
   *
   * @return {Cache}
   */
  incrementExpiration(key, seconds) {
    this.redis.expire(key, seconds)
    return this
  }
}

module.exports = Redis

Refactor to use dependency injection


import Conductor from 'conductor';
import ajax from 'glazier/utils/ajax';

/*
  Provides unauthenticated github api access

  @class UnauthenticatedGithubApiConsumer
*/
var UnauthenticatedGithubApiService = Conductor.Oasis.Service.extend({

  /*
    @public

    @property requests
    @type Object
  */
  requests: {

    /*
      @public

      @method ajax
      @param ajaxOpts {Object}
    */
    ajax: function (ajaxOpts) {
      var card = this.card;

      ajaxOpts.data = ajaxOpts.data = {};

      var url = 'https://api.github.com' + ajaxOpts.url;

      delete ajaxOpts.url;
      delete ajaxOpts.data.access_token;

      return ajax(url, ajaxOpts).then(null, failureResultFromJqXhr);
    }
  }
});

function failureResultFromJqXhr(jqXhr){
  var parsedError = {
    responseText: jqXhr.responseText,
    status: jqXhr.status,
    rawHeaders: jqXhr.getAllResponseHeaders()
  };

  throw parsedError;
}

export default UnauthenticatedGithubApiService;

import Conductor from 'conductor';
import ajax from 'glazier/utils/ajax';

/*
  Provides unauthenticated github api access

  @class UnauthenticatedGithubApiConsumer
*/
var UnauthenticatedGithubApiService = Conductor.Oasis.Service.extend({

  /*
    @public

    @property requests
    @type Object
  */
  requests: {

    /*
      @public

      @method ajax
      @param ajaxOpts {Object}
    */
    ajax: function (ajaxOpts) {
      var card = this.card;

      ajaxOpts.data = ajaxOpts.data = {};

      var url = 'https://api.github.com' + ajaxOpts.url;

      delete ajaxOpts.url;
      delete ajaxOpts.data.access_token;

      return ajax(url, ajaxOpts).then(null, failureResultFromJqXhr);
    }
  }
});

function failureResultFromJqXhr(failureTriple){
  var jqXhr = failureTriple[0],
      parsedError = {
        responseText: jqXhr.responseText,
        status: jqXhr.status,
        rawHeaders: jqXhr.getAllResponseHeaders()
      };

  throw parsedError;
}

export default UnauthenticatedGithubApiService;

Apply new ajax adjustment to unauthenticatedGithubApiService too.


/* @flow */
import React, { PureComponent } from 'react';
import { StyleSheet } from 'react-native';

import type { Actions, Auth } from '../types';
import connectWithActions from '../connectWithActions';
import { ZulipButton } from '../common';
import { unregisterPush } from '../api';
import { getAuth, getAccounts, getPushToken } from '../selectors';
import { logErrorRemotely } from '../utils/logging';

const styles = StyleSheet.create({
  logoutButton: {
    flex: 1,
    margin: 8,
  },
});

type Props = {
  accounts: any[],
  auth: Auth,
  pushToken: string,
  actions: Actions,
};

class LogoutButton extends PureComponent<Props> {
  props: Props;

  shutdownPUSH = async () => {
    const { auth, actions, pushToken } = this.props;
    if (pushToken !== '') {
      try {
        await unregisterPush(auth, pushToken);
      } catch (e) {
        logErrorRemotely(e, 'failed to unregister Push token');
      }
      actions.deleteTokenPush();
    }
  };

  logout = () => {
    const { accounts, actions } = this.props;
    this.shutdownPUSH();
    actions.logout(accounts);
  };

  render() {
    return (
      <ZulipButton style={styles.logoutButton} secondary text="Logout" onPress={this.logout} />
    );
  }
}

export default connectWithActions(state => ({
  auth: getAuth(state),
  accounts: getAccounts(state),
  pushToken: getPushToken(state),
}))(LogoutButton);

/* @flow */
import React, { PureComponent } from 'react';
import { StyleSheet } from 'react-native';

import type { Actions, Auth } from '../types';
import connectWithActions from '../connectWithActions';
import { ZulipButton } from '../common';
import { unregisterPush } from '../api';
import { getAuth, getPushToken } from '../selectors';
import { logErrorRemotely } from '../utils/logging';

const styles = StyleSheet.create({
  logoutButton: {
    flex: 1,
    margin: 8,
  },
});

type Props = {
  auth: Auth,
  pushToken: string,
  actions: Actions,
};

class LogoutButton extends PureComponent<Props> {
  props: Props;

  shutdownPUSH = async () => {
    const { auth, actions, pushToken } = this.props;
    if (pushToken !== '') {
      try {
        await unregisterPush(auth, pushToken);
      } catch (e) {
        logErrorRemotely(e, 'failed to unregister Push token');
      }
      actions.deleteTokenPush();
    }
  };

  logout = () => {
    const { actions } = this.props;
    this.shutdownPUSH();
    actions.logout();
  };

  render() {
    return (
      <ZulipButton style={styles.logoutButton} secondary text="Logout" onPress={this.logout} />
    );
  }
}

export default connectWithActions(state => ({
  auth: getAuth(state),
  pushToken: getPushToken(state),
}))(LogoutButton);

Clean up logout method call.


/* global Firebase */
'use strict';

/**
 * @ngdoc service
 * @name bannerPreviewApp.BannerService
 * @description
 * # BannerService
 * Service in the bannerPreviewApp.
 */
angular.module('bannerPreviewApp')
  .service('BannerService', function BannerService($firebase, configuration) {
    this.getBanners = function() {
      var ref = new Firebase(configuration.firebaseUrl);
      var sync = $firebase(ref);

      return sync.$asObject();
    };
  });

/* global Firebase */
'use strict';

/**
 * @ngdoc service
 * @name bannerPreviewApp.BannerService
 * @description
 * # BannerService
 * Service in the bannerPreviewApp.
 */
angular.module('bannerPreviewApp')
  .service('BannerService', function BannerService($firebase, configuration) {
    this.getBanners = function() {
      var ref = new Firebase(configuration.firebaseUrl);
      var sync = $firebase(ref);

      return sync.$asObject();
    };

    this.getBanner = function(id) {
      var ref = new Firebase(configuration.firebaseUrl + '/' + id);
      var sync = $firebase(ref);

      return sync.$asObject();
    };
  });

Add getBanner method to BannerService


define( [ "Ember", "EmberData", "EmberDataLS" ], function( Ember, DS ) {

	// no initializer here: just upgrade the application store

	var merge = Ember.merge;

	DS.Store.reopen({
		/**
		 * Find a record and unload the generated record
		 * @param {string} modelName
		 * @param {string|number} id
		 * @param {Object?} options
		 * @param {boolean?} options.reload
		 * @returns {Promise.<DS.Model?>}
		 */
		findExistingRecord: function( modelName, id, options ) {
			var store = this;
			options = merge( { reload: true }, options );

			return store.findRecord( modelName, id, options )
				.catch(function() {
					// unload the generated empty record
					var record = store.peekRecord( modelName, id );
					if ( record ) {
						store.unloadRecord( record );
					}
					return Promise.reject();
				});
		}
	});

});

define( [ "Ember", "EmberData", "EmberDataLS" ], function( Ember, DS ) {

	// no initializer here: just upgrade the application store

	var merge = Ember.merge;

	DS.Store.reopen({
		/**
		 * Find a record and unload the generated record
		 * @param {string} modelName
		 * @param {string|number} id
		 * @param {Object?} options
		 * @param {boolean?} options.reload
		 * @returns {Promise.<DS.Model?>}
		 */
		findExistingRecord: function( modelName, id, options ) {
			var store = this;
			options = merge( { reload: true }, options );

			return store.findRecord( modelName, id, options )
				.catch(function() {
					// unload the generated empty record
					var record = store.peekRecord( modelName, id );
					if ( record ) {
						store.unloadRecord( record );
					}
					return Promise.reject();
				});
		},

		query: function() {
			return this._super.apply( this, arguments )
				.then(function( recordArray ) {
					recordArray._unregisterFromManager();
					return recordArray;
				});
		}
	});

});

Fix memory leak in EmberData's RecordArrayManager


const limit = require('../../lib/query-builder/v2/limit');
const project = require('../../lib/query-builder/v2/project');

module.exports = {

  /**
   * Returns all Dragon data
   */
  all: async (ctx) => {
    const data = await global.db
      .collection('dragon')
      .find({})
      .project(project(ctx.request.query))
      .limit(limit(ctx.request.query))
      .toArray();
    ctx.body = data;
  },

  /**
   * Returns specific Dragon data
   */
  specific: async (ctx) => {
    const data = await global.db
      .collection('dragon')
      .find({ id: ctx.params.capsule })
      .project(project(ctx.request.query))
      .toArray();
    [ctx.body] = data;
  },

};

const limit = require('../../lib/query-builder/v2/limit');
const project = require('../../lib/query-builder/v2/project');

module.exports = {

  /**
   * Returns all Dragon data
   */
  all: async (ctx) => {
    const data = await global.db
      .collection('dragon')
      .find({})
      .project(project(ctx.request.query))
      .sort({ id: 1 })
      .limit(limit(ctx.request.query))
      .toArray();
    ctx.body = data;
  },

  /**
   * Returns specific Dragon data
   */
  specific: async (ctx) => {
    const data = await global.db
      .collection('dragon')
      .find({ id: ctx.params.capsule })
      .project(project(ctx.request.query))
      .toArray();
    [ctx.body] = data;
  },

};

Fix order in v2 dragon endpoint


import addFavicon from './helpers';
import LazyLoad from 'vanilla-lazyload';
const bowser = require('bowser');

if (bowser.msie && bowser.version < 11) {
  $('.browser').removeClass('hide');
} else if (bowser.chrome && bowser.version < 64) {
  $('.browser').removeClass('hide');
} else if (bowser.firefox  && bowser.version < 58) {
  $('.browser').removeClass('hide');
}

$(document).ready(() => {
  new LazyLoad();

  $(document).foundation();

  if(document.cookie.indexOf('cookie_enabled') == -1)
  {
    $('.header__cookies').removeClass('hide');
  }
  $('#js-cookie__validate').click(() => {
    if(document.cookie.indexOf('cookie_enabled') == -1)
    {
      document.cookie = 'cookie_enabled=true; expires=Fri, 3 Aug 2100 20:47:11 UTC; path=/';
      $('.header__cookies').addClass('hide');
    }
  });

  addFavicon();

});

import addFavicon from './helpers';
import LazyLoad from 'vanilla-lazyload';
const bowser = require('bowser');

if (bowser.msie) {
  $('.browser').removeClass('hide');
} else if (bowser.msedge && bowser.version < 12) {
  $('.browser').removeClass('hide');
} else if (bowser.chrome && bowser.version < 64) {
  $('.browser').removeClass('hide');
} else if (bowser.firefox  && bowser.version < 58) {
  $('.browser').removeClass('hide');
}

$(document).ready(() => {
  new LazyLoad();

  $(document).foundation();

  if(document.cookie.indexOf('cookie_enabled') == -1)
  {
    $('.header__cookies').removeClass('hide');
  }
  $('#js-cookie__validate').click(() => {
    if(document.cookie.indexOf('cookie_enabled') == -1)
    {
      document.cookie = 'cookie_enabled=true; expires=Fri, 3 Aug 2100 20:47:11 UTC; path=/';
      $('.header__cookies').addClass('hide');
    }
  });

  addFavicon();

});

Add message browser out of date for all msie


$(window).load(function(){

    var selector = '.settings-nav li';
    $(selector).not(".collapse-li").click(function () {
        $(selector).not(".collapse-li").removeClass('active');
    });

    // Show the relevant tab from url
    var url = document.location.toString();
    if (url.match('#')) {
        $('.settings-nav a[href="#' + url.split('#')[1] + '"]').tab('show');
    } else {
        $('.settings-content > .tab-pane:first-child').addClass('active');
        $('.settings-nav > ul > li:first-child a').removeClass('collapsed');
        $('#profile-menu li:first-child').addClass('active');
    }

    $( ".sub-menu" ).each(function( index ) {
        if ($(this).children('li').hasClass('active')) {
            $(this).addClass('in');
        }
    });

    // Change hash for select tab
    $('.settings-nav a, .sub-menu a').on('shown.bs.tab', function (e) {
        window.location.hash = e.target.hash;
        $(window).scrollTop(0);
    });
});

$(window).load(function(){

    var selector = '.settings-nav li';
    $(selector).not(".collapse-li").click(function () {
        $(selector).not(".collapse-li").removeClass('active');
    });

    // Show the relevant tab from url
    var url = document.location.toString();
    if (url.match('#')) {
        $('.settings-nav a[href="#' + url.split('#')[1] + '"]').tab('show');
    } else {
        $('.settings-content > .tab-pane:first-child').addClass('active');
        $('.settings-nav > ul > li:first-child a').removeClass('collapsed');
        $('#profile-menu li:first-child').addClass('active');
    }

    $( ".sub-menu" ).each(function( index ) {
        if ($(this).children('li').hasClass('active')) {
            $(this).addClass('in');
        }
    });

    // Change hash for select tab
    $('.settings-nav a, .sub-menu a').on('shown.bs.tab', function (e) {
        window.location.hash = e.target.hash;
        $(window).scrollTop(0);
    });

    $('input[readonly]').on('focus', function () {
        this.blur();
    });
});

Remove focus effect on readonly fields


define(['jquery', 'dialog', 'rpcClient'], function($, Dialog, RpcClient) {
    function AddTorrentsDialog() {
        Dialog.call(this, '/plugins/core.torrents/dialogs/add-torrents.html');
        this.rpc = new RpcClient();
    }

    AddTorrentsDialog.prototype = new Dialog();
    AddTorrentsDialog.prototype.constructor = AddTorrentsDialog;

    AddTorrentsDialog.prototype.load = function (callback) {
        callback();
    };

    return AddTorrentsDialog;
});

define(['jquery', 'dialog', 'rpcClient'], function($, Dialog, RpcClient) {
    function AddTorrentsDialog() {
        Dialog.call(this, '/plugins/core.torrents/dialogs/add-torrents.html');
        this.rpc = new RpcClient();
    }

    AddTorrentsDialog.prototype = new Dialog();
    AddTorrentsDialog.prototype.constructor = AddTorrentsDialog;

    AddTorrentsDialog.prototype.load = function (callback) {
        var that = this;
        this.content.find('#btn-add-torrents').on('click', function(e) {
            e.preventDefault();
            that.addTorrents();
        });

        callback();
    };

    AddTorrentsDialog.prototype.addTorrents = function () {
        this.content.find('#btn-add-torrents').attr('disabled', true);

        var fileInput = this.content.find('#torrent-files')[0];
        var reader = new FileReader();
        var filesAdded = 0;
        var that = this;

        reader.onload = function(e) {
            var data = [
                e.target.result.split(',')[1],
                '',
                ''
            ];

            that.rpc.callParams('torrents.addFile', data, function() {
                filesAdded += 1;

                if (filesAdded == fileInput.files.length) {
                    that.close();
                }
            });
        };

        for (var i = 0; i < fileInput.files.length; i++) {
            reader.readAsDataURL(fileInput.files[i]);
        }
    };

    return AddTorrentsDialog;
});

Add torrent dialog now adds torrents.


sap.ui.define([
	"sap/ui/base/Object"
], function (UI5Object) {
	"use strict";

	return UI5Object.extend("sap.ui.demo.wt.controller.HelloDialog", {

		constructor : function (oView) {
			this._oView = oView;
		},

		open : function () {
			var oView = this._oView;
			var oDialog = oView.byId("helloDialog");

			// create dialog lazily
			if (!oDialog) {
				var oFragmentController = {
					onCloseDialog : function () {
						oDialog.close();
					}
				};
				// create dialog via fragment factory
				oDialog = sap.ui.xmlfragment(oView.getId(), "sap.ui.demo.wt.view.HelloDialog", oFragmentController);
				// connect dialog to the root view of this component (models, lifecycle)
				oView.addDependent(oDialog);
				// forward compact/cozy style into dialog
				jQuery.sap.syncStyleClass(this._oView.getController().getOwnerComponent().getContentDensityClass(), this._oView, this._oDialog);
			}
			oDialog.open();
		}

	});

});

sap.ui.define([
	"sap/ui/base/Object"
], function (UI5Object) {
	"use strict";

	return UI5Object.extend("sap.ui.demo.wt.controller.HelloDialog", {

		constructor : function (oView) {
			this._oView = oView;
		},

		open : function () {
			var oView = this._oView;
			var oDialog = oView.byId("helloDialog");

			// create dialog lazily
			if (!oDialog) {
				var oFragmentController = {
					onCloseDialog : function () {
						oDialog.close();
					}
				};
				// create dialog via fragment factory
				oDialog = sap.ui.xmlfragment(oView.getId(), "sap.ui.demo.wt.view.HelloDialog", oFragmentController);
				// connect dialog to the root view of this component (models, lifecycle)
				oView.addDependent(oDialog);
				// forward compact/cozy style into dialog
				jQuery.sap.syncStyleClass(oView.getController().getOwnerComponent().getContentDensityClass(), oView, oDialog);
			}
			oDialog.open();
		}

	});

});

Fix walkthrough step 37 after simplification


module.exports = TimestreamDB
module.exports.open = function (path, options, callback) {
  // TODO force valueEncoding = json?
  if (callback) {
    levelup(path, options, function (err, db) {
      if (err) return callback(err)
      callback(err, TimestreamDB(db, options))
    })
  }
  else
    return TimestreamDB(levelup(path, options), options)
}

var levelup = require("levelup")
var Version = require("level-version")
var through2map = require("through2-map")
var ts = require("timestream")

var toTimestream = through2map.ctor({objectMode: true},
  function _transform(record) {
    var tsRecord = record.value
    tsRecord._t = record.version
    tsRecord._key = record.key
    return tsRecord
  }
)

/**
 * Create a new TimestreamDB
 * @param {LevelUp} instance   A LevelUp instance
 * @param {object} options Configuration options for level-version
 */
function TimestreamDB(instance, options) {
  if (!(this instanceof TimestreamDB))
    return new TimestreamDB(instance, options)

  var db = Version(instance, options)

  db.ts = function (key) {
    return ts(db.versionStream(key, {reverse: true}).pipe(toTimestream()))
  }
  db.timeStream = db.ts

  return db
}

module.exports = TimestreamDB
module.exports.open = function (path, options, callback) {
  // TODO force valueEncoding = json?
  if (callback) {
    levelup(path, options, function (err, db) {
      if (err) return callback(err)
      callback(err, TimestreamDB(db, options))
    })
  }
  else
    return TimestreamDB(levelup(path, options), options)
}

var levelup = require("levelup")
var Version = require("level-version")
var through2map = require("through2-map")
var ts = require("timestream")

var toTimestream = through2map.ctor({objectMode: true},
  function _transform(record) {
    var tsRecord = record.value
    tsRecord._t = record.version
    tsRecord._key = record.key
    return tsRecord
  }
)

/**
 * Create a new TimestreamDB
 * @param {LevelUp} instance   A LevelUp instance
 * @param {object} options Configuration options for level-version
 */
function TimestreamDB(instance, options) {
  if (!(this instanceof TimestreamDB))
    return new TimestreamDB(instance, options)

  var db = Version(instance, options)

  db.ts = function (key, options) {
    var opts = {reverse: true}

    if (options.start) opts.minVersion = options.start
    if (options.until) opts.maxVersion = options.until
    return ts(db.versionStream(key, opts).pipe(toTimestream()))
  }
  db.timeStream = db.ts

  return db
}

Add support for start and end ranges at query time


import m from 'mithril';

import { OptionsDisplayTable } from './options-display-table';
import { NewOptionForm } from './new-option-form';
import { OptionsMenu } from './options-menu';

export class OptionsPage {
	view() {
		return m('div', [
			m(OptionsMenu),
			m(NewOptionForm),
			m(OptionsDisplayTable)
		])
	}
}

import m from 'mithril';

import { OptionsDisplayTable } from './options-display-table';
import { NewOptionForm } from './new-option-form';
import { OptionsMenu } from './options-menu';

export class OptionsPage {
	view() {
		return m('div.p-3', [
			m(OptionsMenu),
			m(NewOptionForm),
			m(OptionsDisplayTable)
		])
	}
}

Add padding to application container div


// TODO Don't use a global
var proofRows = [];

// TODO Don't use a global
var proofTBody = document.getElementById("theTable").createTBody();

function makeProofLine(formulaText, reasonText) {
    formulaText = formulaText || "";
    reasonText = reasonText || "";

    var newId = proofRows.length;
    var row = document.createElement("tr");
    proofRows[newId] = row;

    var idCell = row.insertCell();
    idCell.innerText = newId;

    var formulaInput = document.createElement("input");
    formulaInput.className = "formula";
    formulaInput.value = formulaText;
    row.insertCell().appendChild(formulaInput);

    var reasonInput = document.createElement("input");
    reasonInput.value = reasonText;
    row.insertCell().appendChild(reasonInput);

    return newId;
}

function moveAbove(topRow, botRow) {
    proofTBody.insertBefore(proofRows[topRow], proofRows[botRow]);
}

function setFormula(row, formulaHtml) {
    proofRows[row].children[1].innerHTML = formulaHtml;
}

function setReason(row, reasonHtml) {
    proofRows[row].children[2].innerHTML = reasonHtml;
}

// TODO Don't use a global
var proofRows = [];

// TODO Don't use a global
var proofTable = document.getElementById("theTable");

var escapingDiv = document.createElement("div");

proofTable.addEventListener("change", function (changeEvent) {
    // TODO May be a security risk -- also annoying to type HTML entities
    escapingDiv.innerHTML = changeEvent.target.value;
    changeEvent.target.value = escapingDiv.innerHTML;
});

// TODO Don't use a global
var proofTBody = proofTable.createTBody();

function makeProofLine(formulaText, reasonText) {
    formulaText = formulaText || "";
    reasonText = reasonText || "";

    var newId = proofRows.length;
    var row = document.createElement("tr");
    proofRows[newId] = row;

    var idCell = row.insertCell();
    idCell.innerText = newId;

    var formulaInput = document.createElement("input");
    formulaInput.className = "formula";
    formulaInput.value = formulaText;
    row.insertCell().appendChild(formulaInput);

    var reasonInput = document.createElement("input");
    reasonInput.value = reasonText;
    row.insertCell().appendChild(reasonInput);

    return newId;
}

function moveAbove(topRow, botRow) {
    proofTBody.insertBefore(proofRows[topRow], proofRows[botRow]);
}

function setFormula(row, formulaHtml) {
    proofRows[row].children[1].innerHTML = formulaHtml;
}

function setReason(row, reasonHtml) {
    proofRows[row].children[2].innerHTML = reasonHtml;
}

Allow math symbols to be input via character entities


define(['jquery'], function ($) {
    var colors = {
        log: '#000000',
        warn: '#cc9900',
        error: '#cc0000'
    };

    var log = $('#log');

    if (!console) {
        console = {};
    }
    for (var name in colors) {
        console[name] = (function (original, color) {
            return function () {
                func.apply(console, arguments);

                var line = $('<div>');
                log.append(line);
                for (var i = 0; i < arguments.length; i++) {
                    var section = $('<span>');
                    section.text(arguments[i]);
                    line.append(section);
                    line.css('color', color);
                }
            };
        })(console[name] || function() {}, colors[name]);
    }
    return console;
});

define(['jquery'], function ($) {
    var colors = {
        log: '#000000',
        warn: '#cc9900',
        error: '#cc0000'
    };

    var log = $('#log');

    if (!console) {
        console = {};
    }
    for (var name in colors) {
        console[name] = (function (original, color) {
            return function () {
                original.apply(console, arguments);

                var line = $('<div>');
                log.append(line);
                for (var i = 0; i < arguments.length; i++) {
                    var section = $('<span>');
                    section.text(arguments[i]);
                    line.append(section);
                    line.css('color', color);
                }
            };
        })(console[name] || function() {}, colors[name]);
    }
    return console;
});

Rename the used variable everywhere, and not just in its definition...


import { createSelector } from 'reselect';
import * as deps from '../deps';
import * as selectors from '../selectors';

export const getSettings = packageNamespace =>
  createSelector(
    selectors.getSettingsLiveCollection,
    deps.selectors.getSelectedSiteId,
    (settings, siteId) =>
      settings.find(
        item => item.woronaInfo.namespace === packageNamespace && item.woronaInfo.siteId === siteId,
      ) || { woronaInfo: {} }, // default to empty object til settings collections is loaded
  );

export const getSetting = (packageNamespace, settingName, settingDefault = undefined) =>
    createSelector(
      getSettings(packageNamespace),
      settings => settings && settings[settingName] || settingDefault,
    );

import { createSelector } from 'reselect';
import * as deps from '../deps';
import * as selectors from '../selectors';

export const getSettings = packageNamespace =>
  createSelector(
    selectors.getSettingsLiveCollection,
    deps.selectors.getActivatedPackages,
    deps.selectors.getSelectedSiteId,
    (settings, activated, siteId) =>
      settings.find(
        item =>
          item.woronaInfo.name === activated[packageNamespace] && item.woronaInfo.siteId === siteId,
      ) || { woronaInfo: {} }, // default to empty object til settings collections is loaded
  );

export const getSetting = (packageNamespace, settingName, settingDefault = undefined) =>
  createSelector(
    getSettings(packageNamespace),
    settings => (settings && settings[settingName]) || settingDefault,
  );

Remove the need of namespaces in settings.


// Factlink configuration
//= require_tree ./globals

// All the default libraries/files needed for all pages on Factlink
//= require local_storage_polyfill
//= require underscore
//= require console_polyfill
//= require function_bind_polyfill
//= require jquery_ujs
//= require jquery.scrollTo
//= require jquery_ujs_override
//= require jquery.placeholder
//= require ohnoes

//= require_tree ./base
//= require_tree ./lib
//= require postFactlinkObject
//= require factlink.backbone

// Factlink configuration
//= require_tree ./globals

// All the default libraries/files needed for all pages on Factlink
//= require console_polyfill
//= require function_bind_polyfill
//= require local_storage_polyfill

//= require jquery_ujs
//= require jquery.scrollTo
//= require jquery_ujs_override
//= require jquery.placeholder

//= require underscore
//= require ohnoes

//= require_tree ./base
//= require_tree ./lib
//= require postFactlinkObject
//= require factlink.backbone

Move polyfills into their own seperate section


export const baseStyles = {
  height: '100vh',
};

export const centerStyles = {
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center'
};

export const baseStyles = {};

export const centerStyles = {
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center'
};

Remove the height: 100vh from baseStyles which breaks the viewport scrolling


var monk = require('monk');
module.exports = monk('localhost:27017/frozen-forest');

var monk = require('monk');
module.exports = monk(process.env.MONGOHQ_URL || 'localhost:27017/frozen-forest');

Use MongoHQ URI if available.


angular.module('sparrow')
.controller('TimedCtrl', function() {

})
.component('timed', {
  controller: 'TimedCtrl',
  templateUrl: 'templates/timed.html'
});

angular.module('sparrow')
.controller('TimedCtrl', function() {
  this.workout = [];
  //workout  contain template created by user.
  this.addWorkout = function() {
    var obj = {};
    obj.activity = this.activity;
    obj.duration = Number(this.minutes || 0) * 60 + Number(this.seconds);
    this.workout.push(obj);
  };
})
.component('timed', {
  controller: 'TimedCtrl',
  templateUrl: 'templates/timed.html'
});

Add addWorkout() which help create a template of workout


(function(){
'use strict';

angular
  .module('secondLead',
  	['ngDragDrop',
  	'ui.bootstrap',
  	'ui.router',
  	'gridster',
  	'restangular',
    'angularUtils.directives.dirPagination',
    'secondLead.common',
  	'templates'])

  .config(function(paginationTemplateProvider) {
    paginationTemplateProvider.setPath('/dirPagination.html');
  })

  .config(['$stateProvider',
    '$urlRouterProvider',
    function($stateProvider, $urlRouterProvider) {
    $stateProvider

      .state('dramas-model', {
        url:'/dramas',
        templateUrl: 'dramas-index.html',
        controller:'DramasCtrl',
        controllerAs: 'dramas'
      });

    $urlRouterProvider.otherwise('/');
  }]);

})();

(function(){
'use strict';

angular
  .module('secondLead',
  	['ngDragDrop',
  	'ui.bootstrap',
  	'ui.router',
  	'gridster',
  	'restangular',
    'angularUtils.directives.dirPagination',
    'secondLead.common',
  	'templates'])

  .config(function(paginationTemplateProvider) {
    paginationTemplateProvider.setPath('/dirPagination.html');
  })

  .config(['$stateProvider',
    '$urlRouterProvider',
    function($stateProvider, $urlRouterProvider) {
    $stateProvider

      .state('dramas-model', {
        url:'/dramas',
        templateUrl: 'dramas-index.html',
        controller:'DramasCtrl',
        controllerAs: 'dramas'
      });

      .state('users-model', {
        url:'/users',
        templateUrl: 'user-show.html',
        controller:'UserCtrl',
        controllerAs: 'user'
      });

    $urlRouterProvider.otherwise('/');
  }]);

})();

Add stateProvider state for user


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

function kml() {}

kml.prototype = new ogr('kml');

var p = kml.prototype;

p._contentType = "application/kml; charset=utf-8";
p._fileExtension = "kml";
// As of GDAL 1.10 SRID detection is bogus, so we use
// our own method. See:
//  http://trac.osgeo.org/gdal/ticket/5131
//  http://trac.osgeo.org/gdal/ticket/5287
//  http://github.com/CartoDB/CartoDB-SQL-API/issues/110
//  http://github.com/CartoDB/CartoDB-SQL-API/issues/116
p._needSRS = true;

p.generate = function(options, callback) {
    var o = options;
    this.toOGR_SingleFile(o.database, o.user_id, o.gn, o.sql, o.skipfields, 'KML', 'kml', o.filename, callback);
};

module.exports = kml;

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

function kml() {}

kml.prototype = new ogr('kml');

var p = kml.prototype;

p._contentType = "application/kml; charset=utf-8";
p._fileExtension = "kml";
// As of GDAL 1.10.1 SRID detection is bogus, so we use
// our own method. See:
//  http://trac.osgeo.org/gdal/ticket/5131
//  http://trac.osgeo.org/gdal/ticket/5287
//  http://github.com/CartoDB/CartoDB-SQL-API/issues/110
//  http://github.com/CartoDB/CartoDB-SQL-API/issues/116
// Bug was fixed in GDAL 1.10.2
p._needSRS = true;

p.generate = function(options, callback) {
    var o = options;
    this.toOGR_SingleFile(o.database, o.user_id, o.gn, o.sql, o.skipfields, 'KML', 'kml', o.filename, callback);
};

module.exports = kml;

Add note about which GDAL version fixes the SRID detection bug


$(document).ready(function() {
    $(window).listHistory();

    $("select, input[type='radio']", ".filter-form").loader({
        trigger_on_event: "change"
    });
    $("button[type='submit']", ".filter-form").loader();
    $("button.refresh-btn", ".filter-form").cleaner();
    $('div.content')
    .per_page_paginator({bindMethod: 'live', selector: 'div.content-footnote .per-page a'})
    .page_paginator({bindMethod: 'live', selector: 'div.content-footnote .pagination a'});
});

$(document).ready(function() {
    $(window).listHistory();
    $(".link-export").click(function() {
        $(this).attr("href", $.clear_query_params($(this).attr("href")) + window.location.search);
    });
    $("select, input[type='radio']", ".filter-form").loader({
        trigger_on_event: "change"
    });
    $("button[type='submit']", ".filter-form").loader();
    $("button.refresh-btn", ".filter-form").cleaner();
    $('div.content').per_page_paginator({
        bindMethod: 'live',
        selector: 'div.content-footnote .per-page a'
    }).page_paginator({
        bindMethod: 'live',
        selector: 'div.content-footnote .pagination a'
    });
});

Add form params to PDF 'link-export' link


import { createSelector } from 'reselect';
import { selectArticles } from './articles';
import { selectEvents } from './events';

export const selectFrontpage = createSelector(
  selectArticles,
  selectEvents,
  (articles, events) => {
    return articles.concat(events);
  }
);

import moment from 'moment';
import { sortBy } from 'lodash';
import { createSelector } from 'reselect';
import { selectArticles } from './articles';
import { selectEvents } from './events';

export const selectFrontpage = createSelector(
  selectArticles,
  selectEvents,
  (articles, events) =>
    sortBy(articles.concat(events), item => {
      const timeField = item.eventType ? item.startTime : item.createdAt;
      return Math.abs(moment() - moment(timeField));
    })
);

Sort events and articles by dates from now


'use strict';

const browsers = [
  'last 1 Chrome versions',
  'last 1 Firefox versions',
  'last 1 Safari versions'
];

const isCI = !!process.env.CI;
const isProduction = process.env.EMBER_ENV === 'production';

if (isCI || isProduction) {
  browsers.push('ie 11');
}

module.exports = {
  browsers
};

Fix 'const' declarations in non-strict mode are not supported


import React from 'react'
import { shallow } from 'enzyme'

import { MobilizationPage } from '../../pages/mobilization-page'

describe('app/modules/mobilizations/__tests__/pages/mobilization-page', () => {
  const defaultProps = { mobilization: {} }
  const context = { router: {} }

  it('should render without crashed', () => {
    shallow(<MobilizationPage {...defaultProps} />, { context })
  })
})

import React from 'react'
import { shallow } from 'enzyme'

import { MobilizationPage } from './mobilization-page'

describe('app/modules/mobilizations/pages/mobilization-page', () => {
  const defaultProps = { mobilization: {} }
  const context = { router: {} }

  it('should render without crashed', () => {
    shallow(<MobilizationPage {...defaultProps} />, { context })
  })
})

Fix mobilization page test file import


<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-69304119-2', 'auto');
  ga('send', 'pageview');

</script>

Resolve a bug due to GA tracker code


import { graphqlExpress } from 'apollo-server-express';
import 'isomorphic-fetch';

import schema from '../api/schema';
import modules from '../modules';
import settings from '../../../settings';
import log from '../../common/log';

export default graphqlExpress(async (req, res, next) => {
  try {
    return {
      schema,
      context: await modules.createContext(req, res),
      debug: false,
      formatError: error => {
        log.error('GraphQL execution error:', error);
        return error;
      },
      tracing: !!settings.engine.engineConfig.apiKey,
      cacheControl: !!settings.engine.engineConfig.apiKey
    };
  } catch (e) {
    next(e);
  }
});

import { graphqlExpress } from 'apollo-server-express';
import 'isomorphic-fetch';

import schema from '../api/schema';
import modules from '../modules';
import settings from '../../../settings';
import log from '../../common/log';

export default graphqlExpress(async (req, res) => {
  return {
    schema,
    context: await modules.createContext(req, res),
    debug: false,
    formatError: error => {
      log.error('GraphQL execution error:', error);
      return error;
    },
    tracing: !!settings.engine.engineConfig.apiKey,
    cacheControl: !!settings.engine.engineConfig.apiKey
  };
});

Fix errors handling in GraphQL middleware


'use strict';

const config = {
    repository_url: 'github.com/zulhilmizainuddin/url-shortener',
    base_url: 'localhost:7000',
    log_level: 'info',
    memcached_server: 'url-shortener:11211',
    cache_lifetime: 60
};

module.exports = config;

'use strict';

const config = {
    repository_url: 'github.com/zulhilmizainuddin/url-shortener',
    base_url: 'localhost:7000',
    log_level: 'info',
    memcached_server: 'url-cache:11211',
    cache_lifetime: 60
};

module.exports = config;

Update memcached server location for Docker


(function() {

    reactDemo();
    boringDemo();

    function reactDemo() {

        document.getElementById('react-touch-demo').addEventListener('loadedmetadata', function() {
            this.currentTime = 43;
        }, false);

    }

    function boringDemo() {

        var menuButton = document.getElementsByClassName('menu-toggle')[0],
            menu = document.getElementsByClassName('menu')[0];

        menuButton.onclick = function(event) {

            if( menu.classList.contains('reveal') ) {
                menu.classList.remove('reveal');
            } else {
                menu.classList.add('reveal');
            }

            event.preventDefault();

        }

    }

})();

(function() {

    fullScreen();
    reactDemo();
    boringDemo();

    function toggleFullScreen() {
        if (!document.fullscreenElement &&    // alternative standard method
            !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement ) {  // current working methods
            if (document.documentElement.requestFullscreen) {
                document.documentElement.requestFullscreen();
            } else if (document.documentElement.msRequestFullscreen) {
                document.documentElement.msRequestFullscreen();
            } else if (document.documentElement.mozRequestFullScreen) {
                document.documentElement.mozRequestFullScreen();
            } else if (document.documentElement.webkitRequestFullscreen) {
                document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
            }
        } else {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            }
        }
    }

    function fullScreen() {

        document.getElementById('demo-title').onclick = function() {
            toggleFullScreen();
        }

    }

    function reactDemo() {

        document.getElementById('react-touch-demo').addEventListener('loadedmetadata', function() {
            this.currentTime = 43;
        }, false);

    }

    function boringDemo() {

        var menuButton = document.getElementsByClassName('menu-toggle')[0],
            menu = document.getElementsByClassName('menu')[0];

        menuButton.onclick = function(event) {

            if( menu.classList.contains('reveal') ) {
                menu.classList.remove('reveal');
            } else {
                menu.classList.add('reveal');
            }

            event.preventDefault();

        }

    }

})();

Add full screen link via title click


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

export default class Header extends React.Component {
  render() {
    const date = new Date();
    return (
        <footer className="ui inverted vertical footer segment">
          <div className="ui text container">
            © { date.getFullYear() }, All rights reserved
          </div>
        </footer>
    );
  }
}

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

export default class Header extends React.Component {
  render() {
    const date = new Date();
    return (
        <footer className="ui vertical footer segment">
          <div className="ui text container">
            © { date.getFullYear() }, All rights reserved
          </div>
        </footer>
    );
  }
}

Remove not need style class


import 'core-js/es5';
import 'core-js/fn/promise';
import 'core-js/fn/symbol';
import 'core-js/fn/array/from';
import 'core-js/fn/array/iterator';
import 'core-js/fn/array/find';
import 'core-js/fn/string/ends-with';
import 'core-js/fn/string/starts-with';
import 'whatwg-fetch';

import 'moment-timezone/moment-timezone';
import 'moment/locale/ru';

import moment from 'moment';

import timezones from '../data/timezones.json';
import App from './core/app';

moment.tz.load(timezones);

const app = new App();
app.run();

import 'core-js/es5';
import 'core-js/fn/promise';
import 'core-js/fn/symbol';
import 'core-js/fn/array';
import 'core-js/fn/string/ends-with';
import 'core-js/fn/string/starts-with';
import 'whatwg-fetch';

import 'moment-timezone/moment-timezone';
import 'moment/locale/ru';

import moment from 'moment';

import timezones from '../data/timezones.json';
import App from './core/app';

moment.tz.load(timezones);

const app = new App();
app.run();

Bring back the full Array polyfill for now


"use strict";

const CLIEngine = require("eslint").CLIEngine;
const Promise = require("bluebird");
const fs = require("fs");
const path = require("path");
const filePathMatcher = require("../../lib/file-path-matcher");

/**
 *
 * @param {string} file
 * @param {string} srcDir
 * @param {JsTaskConfig} config
 */
module.exports = function (file, srcDir, config)
{
    if (filePathMatcher(file, config.ignoreLintFor))
    {
        return;
    }

    let esLintConfig = {
        configFile: __dirname + "/../../../.eslintrc.yml",
        ignore: false,
        ecmaFeatures: {}
    };

    // set specific options for different file extensions
    switch (path.extname(file))
    {
        case ".jsx":
            esLintConfig.ecmaFeatures.jsx = true;
            break;

        case ".js":
            // continue with linting
            break;

        default:
            // abort linting, as any other file extension is given
            return;
    }

    let engine = new CLIEngine(esLintConfig);
    let formatter = engine.getFormatter();
    let report = engine.executeOnFiles([file]);

    if (report.results)
    {
        // make all paths relative
        report.results = report.results.map(
            (entry) =>
            {
                entry.filePath = path.relative(srcDir, entry.filePath);
                return entry;
            }
        );

        console.log(formatter(report.results));
    }
};

"use strict";

const CLIEngine = require("eslint").CLIEngine;
const Promise = require("bluebird");
const fs = require("fs");
const path = require("path");
const filePathMatcher = require("../../lib/file-path-matcher");

/**
 *
 * @param {string} file
 * @param {string} srcDir
 * @param {JsTaskConfig} config
 */
module.exports = function (file, srcDir, config)
{
    if (filePathMatcher(file, config.ignoreLintFor))
    {
        return;
    }

    let esLintConfig = {
        configFile: __dirname + "/../../../.eslintrc.yml",
        ignore: false,
        ecmaFeatures: {}
    };

    // set specific options for different file extensions
    switch (path.extname(file))
    {
        case ".jsx":
            esLintConfig.ecmaFeatures.jsx = true;
            break;

        case ".js":
            // continue with linting
            break;

        default:
            // abort linting, as any other file extension is given
            return;
    }

    let engine = new CLIEngine(esLintConfig);
    let formatter = engine.getFormatter();
    let report = engine.executeOnFiles([file]);

    if (report.errorCount || report.warningCount)
    {
        // make all paths relative
        report.results = report.results.map(
            (entry) =>
            {
                entry.filePath = path.relative(srcDir, entry.filePath);
                return entry;
            }
        );

        console.log(formatter(report.results));
    }
};

Fix empty lines in JS output


const mongoose = require('mongoose');

const shoesSchema = new mongoose.Schema({
  name: String
});

const Shoes = mongoose.model('Shoes', shoesSchema);
module.exports = Shoes;

/*function listshoes() {
	return a list of all the shoes to be treated
}

*/

/*function getSize(shoe) {
	return the size of a shoe
}
*/

Add comments for desired methods in shoe model


/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *    http: *www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

'use strict';

describe('Controller: ResultdetailCtrl', function () {

  // load the controller's module
  beforeEach(module('ocwUiApp'));

  var ResultdetailCtrl,
    scope;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    ResultdetailCtrl = $controller('ResultdetailCtrl', {
      $scope: scope
    });
  }));

  it('should attach a list of awesomeThings to the scope', function () {
    expect(scope.awesomeThings.length).toBe(3);
  });
});

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *    http: *www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

'use strict';

describe('Controller: ResultdetailCtrl', function () {

  // load the controller's module
  beforeEach(module('ocwUiApp'));

  var ResultdetailCtrl,
    scope;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    ResultdetailCtrl = $controller('ResultdetailCtrl', {
      $scope: scope
    });
  }));
});

Remove temporary test for ResultDetailCtrl


/* eslint babel/semi: "error" */
export AttachmentsController from './controllers/api/v1/AttachmentsController';
export FeedFactoriesController from './controllers/api/v1/FeedFactoriesController';
export GroupsController from './controllers/api/v1/GroupsController';
export PasswordsController from './controllers/api/v1/PasswordsController';
export PostsController from './controllers/api/v1/PostsController';
export SessionController from './controllers/api/v1/SessionController';
export UsersController from './controllers/api/v1/UsersController';

export GroupsControllerV2 from './controllers/api/v2/GroupsController';
export RequestsControllerV2 from './controllers/api/v2/RequestsController';
export UsersControllerV2 from './controllers/api/v2/UsersController';
export StatsControllerV2 from './controllers/api/v2/StatsController';
export ArchivesStatsControllerV2 from './controllers/api/v2/ArchivesStatsController';
export SearchController from './controllers/api/v2/SearchController';
export EventsController from './controllers/api/v2/EventsController';
export CommentLikesController from './controllers/api/v2/CommentLikesController';
export InvitationsController from './controllers/api/v2/InvitationsController';

export { default as AttachmentsController } from './controllers/api/v1/AttachmentsController';
export { default as FeedFactoriesController } from './controllers/api/v1/FeedFactoriesController';
export { default as GroupsController } from './controllers/api/v1/GroupsController';
export { default as PasswordsController } from './controllers/api/v1/PasswordsController';
export { default as PostsController } from './controllers/api/v1/PostsController';
export { default as SessionController } from './controllers/api/v1/SessionController';
export { default as UsersController } from './controllers/api/v1/UsersController';

export { default as GroupsControllerV2 } from './controllers/api/v2/GroupsController';
export { default as RequestsControllerV2 } from './controllers/api/v2/RequestsController';
export { default as UsersControllerV2 } from './controllers/api/v2/UsersController';
export { default as StatsControllerV2 } from './controllers/api/v2/StatsController';
export { default as ArchivesStatsControllerV2 } from './controllers/api/v2/ArchivesStatsController';
export { default as SearchController } from './controllers/api/v2/SearchController';
export { default as EventsController } from './controllers/api/v2/EventsController';
export { default as CommentLikesController } from './controllers/api/v2/CommentLikesController';
export { default as InvitationsController } from './controllers/api/v2/InvitationsController';

Change export syntax for Typescript & eslint


require('babel-register'); // transpile code on the fly
module.exports = require('./server.js');

// Use babel-register to transpile server code on the fly
require('babel-register');
module.exports = require('./server.js');


"use strict";

module.exports = function(imports) {

    let express = imports.modules.express;
    let Promise = imports.modules.Promise;
    let fs = require("fs"); // TODO: put this into initImports
    let util = imports.util;
    let handler = util.handler;

    let Team = imports.models.Team;

    let router = express.Router();

    let pages = {
        signup: "Signup",
        login: "Login",
        "": "Index", // this works
        void: "Void",
    };

    for (let page in pages) {

        router.get("/" + page, handler(function*(req, res) {

            if (req.user) {
                req.user.team = yield Team.findOne(req.user.team);
            }

            res.render("../../morteam-web/src/page.html.ejs", {
                userInfo: req.user,
                page: pages[page],
            });

        }));

    }

    router.get("/js/:page", handler(function*(req, res) {
        let page = req.params.page;
        let file = "../morteam-web/build/" + page + ".js";
        // TODO: use the package fs-promise
        fs.exists(file, function(exists) {
            if (!exists) {
                return res.end("fail"); // AHHHH
            }
            fs.createReadStream(file).pipe(res);
        });
    }));

    return router;

};

"use strict";

module.exports = function(imports) {

    let express = imports.modules.express;
    let Promise = imports.modules.Promise;
    let fs = require("fs"); // TODO: put this into initImports
    let util = imports.util;
    let handler = util.handler;

    let Team = imports.models.Team;

    let router = express.Router();

    let pages = {
        signup: "Signup",
        login: "Login",
        "": "Home", // this works
        void: "Void",
    };

    for (let page in pages) {

        router.get("/" + page, handler(function*(req, res) {

            if (req.user) {
                req.user.team = yield Team.findOne(req.user.team);
            }

            res.render("../../morteam-web/src/page.html.ejs", {
                userInfo: req.user,
                page: pages[page],
            });

        }));

    }

    router.get("/js/:page", handler(function*(req, res) {
        let page = req.params.page;
        let file = "../morteam-web/build/" + page + ".js";
        // TODO: use the package fs-promise
        fs.exists(file, function(exists) {
            if (!exists) {
                return res.end("fail"); // AHHHH
            }
            fs.createReadStream(file).pipe(res);
        });
    }));

    return router;

};

Rename Index view to Home


const IDoneThis = require('../apis/i-done-this');
const Slack = require('../apis/slack');

module.exports = commander => {
  commander
    .command('slack')
    .description('Posts your list of IDoneThis goals for today in Slack.')
    .action(() => {
      const idt = new IDoneThis({
        token: process.env.IDT_TOKEN,
        teamId: process.env.IDT_TEAM_ID,
        userId: process.env.IDT_USER_ID
      });
      const slack = new Slack({
        slackHook: process.env.IDT_SLACK_HOOK
      });

      idt.getEntries('goal')
        .then(entries => {
          if (!entries.length) {
            console.log('You do not have any goals in IDoneThis for today.');
            process.exit(0);
          }

          slack.postMessage(`My list of goals in IDoneThis for today:\n\n${entries}`);
        })
        .then(() => idt.getEntries())
        .then(entries => console.log(entries.toString()));
    });
};

const IDoneThis = require('../apis/i-done-this');
const Slack = require('../apis/slack');

module.exports = commander => {
  commander
    .command('slack')
    .description('Posts your list of IDoneThis goals for today in Slack.')
    .arguments('[type]')
    .action(type => {
      type = type ? type.trim().toLowerCase() : null;
      if ([null, 'goal', 'done'].indexOf(type) === -1) {
        throw new Error('The type argument must be `goal`, `done`, or omitted.');
      }

      const idt = new IDoneThis({
        token: process.env.IDT_TOKEN,
        teamId: process.env.IDT_TEAM_ID,
        userId: process.env.IDT_USER_ID
      });
      const slack = new Slack({
        slackHook: process.env.IDT_SLACK_HOOK
      });

      idt.getEntries(type)
        .then(entries => {
          if (!entries.length) {
            console.log('You do not have any goals in IDoneThis for today.');
            process.exit(0);
          }

          slack.postMessage(`My list of goals in IDoneThis for today:\n\n${entries}`);
        })
        .then(() => idt.getEntries())
        .then(entries => console.log(entries.toString()));
    });
};

Add ability to post goals of a specific type to Slack


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

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

	// Display the execution time of grunt tasks
	require('time-grunt')(grunt);

	/**
	 * Load all grunt-tasks in 'Build/Grunt-Options'.
	 */
	var gruntOptionsObj = require('load-grunt-configs')(grunt, {
		config : {
			src: "Build/Grunt-Options/*.js"
		}
	});
	grunt.initConfig(gruntOptionsObj);

	/**
	 * Load all grunt-plugins that are specified in the 'package.json' file.
	 */
	require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

	/**
	 * Default grunt task.
	 * Compiles all .scss/.sass files with ':dev' options and
	 * validates all js-files inside Resources/Private/Javascripts with JSHint.
	 */
	grunt.registerTask('default', ['compass:dev', 'jshint']);

	/**
	 * Travis CI task
	 * Replaces all replace strings with the standard meta data stored in the package.json
	 * and tests all JS files with JSHint, this task is used by Travis CI.
	 */
	grunt.registerTask('travis', ['replace:init', 'jshint']);

	/**
	 * Load custom tasks
	 * Load all Grunt-Tasks inside the 'Build/Grunt-Tasks' dir.
	 */
	grunt.loadTasks('Build/Grunt-Tasks');
};

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

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

	// Display the execution time of grunt tasks
	require('time-grunt')(grunt);

	// Load all grunt-tasks in 'Build/Grunt-Options'.
	var gruntOptionsObj = require('load-grunt-configs')(grunt, {
		config : {
			src: "Build/Grunt-Options/*.js"
		}
	});
	grunt.initConfig(gruntOptionsObj);

	// Load all grunt-plugins that are specified in the 'package.json' file.
	require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

	/**
	 * Default grunt task.
	 * Compiles all .scss/.sass files with ':dev' options and
	 * validates all js-files inside Resources/Private/Javascripts with JSHint.
	 */
	grunt.registerTask('default', ['compass:dev', 'jshint']);

	/**
	 * Travis CI task
	 * Replaces all replace strings with the standard meta data stored in the package.json
	 * and tests all JS files with JSHint, this task is used by Travis CI.
	 */
	grunt.registerTask('travis', ['replace:init', 'jshint']);

	/**
	 * Load custom tasks
	 * Load all Grunt-Tasks inside the 'Build/Grunt-Tasks' dir.
	 */
	grunt.loadTasks('Build/Grunt-Tasks');
};

Change the comment style for single line comments


module.exports = function(grunt) {
    grunt.initConfig({
        jshint: {
            files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
            options: {
                node: true,
                globals: {},
                white: true,
                indent: 2,
                camelcase: true,
                eqeqeq: true,
                eqnull: true,
                quotmark: true,
                expr: true,
                latedef: true
            }
        },
        mochaTest: {
            test: {
                options: {
                    reporter: 'spec'
                },
                src: ['test/**/*.js']
            }
        }
    });
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.registerTask('default', ['jshint', 'mochaTest']);
};

module.exports = function(grunt) {
    grunt.initConfig({
        jshint: {
            files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
            options: {
                node: true,
                globals: {},
                white: true,
                indent: 2,
                camelcase: true,
                eqeqeq: true,
                eqnull: true,
                quotmark: true,
                expr: true,
                latedef: true
            }
        },
        mochaTest: {
            test: {
                options: {
                    reporter: 'spec',
                    timeout: 5000
                },
                src: ['test/**/*.js']
            }
        }
    });
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.registerTask('default', ['jshint', 'mochaTest']);
};

Set Mocha timout to 5 seconds


module.exports = function (grunt) {

	grunt.initConfig({

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

		clean: {
			build: {
				src: "build"
			}
		},

		copy: {
			build: {
				files: [
					{
						expand: true,
						cwd: 'source/',
						src: ['clever-style-switcher.js'],
						dest: 'build/'
					}
				]
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');

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

module.exports = function (grunt) {

	grunt.initConfig({

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

		clean: {
			build: {
				src: "build"
			}
		},

		copy: {
			build: {
				files: [
					{
						expand: true,
						cwd: 'source/',
						src: ['clever-style-switcher.js'],
						dest: 'build/'
					}
				]
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');

	grunt.registerTask('build', ['clean', 'copy']);

	grunt.registerTask('default', ['build']);
};

Add a build task for Grunt and make it the default.


$(document).ready(function() {
  $('#slides').superslides({
    slide_easing: 'easeInOutCubic',
    slide_speed: 800,
    pagination: true,
    hashchange: true,
    scrollabe: true
  });
});

$(document).ready(function() {
  $('#slides').superslides({
    slide_easing: 'easeInOutCubic',
    slide_speed: 800,
    pagination: true,
    hashchange: true,
    scrollable: true
  });
});

Fix scrollable typo in demo


$(document).ready(function() {
    $('#target').teletype({text: ['software engineer.', 'computer scientist.',
                                'student.', 'explorer.', 'sci-fi lover.']});
    $('#cursor').teletype({text: ['|', ' '], delay: 0, pause: 250});
});

$(document).ready(function() {
    $('#target').teletype({text: ['software engineer.', 'computer scientist.',
                                'student.', 'curious explorer.', 'sci-fi lover.']});
    $('#cursor').teletype({text: ['|', ' '], delay: 0, pause: 250});
});

Fix word phrase for proper grammar


/*
    Copyright 2018  Alfredo Mungo <alfredo.mungo@protonmail.ch>

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to
    deal in the Software without restriction, including without limitation the
    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    sell copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/
if (!Object.fromEntries) {
  Object.defineProperty(Object, 'fromEntries', {
    value(entries) {
      if (!entries || !entries[Symbol.iterator]) { throw new Error('Object.fromEntries() requires a single iterable argument'); }

      const o = {};

      Object.keys(entries).forEach((key) => {
        const [k, v] = entries[key];

        o[k] = v;
      });

      return o;
    },
  });
}

/*
    Copyright 2018  Alfredo Mungo <alfredo.mungo@protonmail.ch>

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to
    deal in the Software without restriction, including without limitation the
    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    sell copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/
if (!Object.fromEntries) {
  Object.defineProperty(Object, 'fromEntries', {
    value(entries) {
      if (!entries || !entries[Symbol.iterator]) { throw new Error('Object.fromEntries() requires a single iterable argument'); }

      return [...entries].reduce((obj, [key, val]) => {
        obj[key]= val
        return obj
      }, {})
    },
  });
}

Fix Object.fromEntries polyfill (for Safari 11)


export class Pagination {
  events () {
    $('[data-role="mobile-pagination"]').on('change', $.proxy(this.goToPage, this))
  }

  goToPage (event) {
    let $current = $(event.currentTarget)
    let nextPageId = $current.val()
    let url = window.location.href.split('?')[0]

    let parameters =  this.getParameters()

    parameters["page"] = nextPageId
    window.location.replace(url + '?' + decodeURIComponent($.param(parameters)))
  }

  getParameters () {
    if (typeof window.location.href.split('?')[1] === 'undefined') {
      return {}
    }

    let parameters = {}
    let queryString = window.location.href.split('?')[1]
    let rawParameters = queryString.split('&')

    $.each(rawParameters, (index, rawParameter) => {
      let parameterPair = rawParameter.split('=')
      parameters[parameterPair[0]] = parameterPair[1]
    })

    return parameters
  }
}

export class Pagination {
  events () {
    $('[data-role="mobile-pagination"]').on('change', $.proxy(this.goToPage, this))
  }

  goToPage (event) {
    let $current = $(event.currentTarget)
    let nextPageId = $current.val()

    this.changePageInUrlAndReload(nextPageId)
  }

  changePageInUrlAndReload (value) {
    const key = 'page'
    let parameters = document.location.search.substr(1).split('&')
    let i = parameters.length

    value = encodeURI(value)

    while (i--) {
      let parameter = parameters[i].split('=')

      if (parameter[0] === key) {
        parameter[1] = value
        parameters[i] = parameter.join('=')
        break
      }
    }

    if (i < 0) {
      parameters[parameters.length] = [key, value].join('=')
    }

    document.location.search = parameters.join('&')
  }
}

Upgrade get params of mobile pagination


'use strict';

const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const { BrowserWindow } = require('electron');

const simulator = root => {
  const WIDTH = 800;
  const HEIGHT = 600;
  //Deserialize project info from projInfo file, contains path to index.html and presence of webpack among other things
  // const projInfo = JSON.parse(fs.readFileSync(path.join(__dirname, '../lib/projInfo.js')));

  let child = spawn(
    'npm',
    ['start'],
    {
      cwd: '/Users/jyamamoto/_personal/Fermionjs/app/export_files',
      stdio: 'inherit',
      env: process.env
    }
  )
  setTimeout(()=>{
      let child = new BrowserWindow({
        width: WIDTH,
        height: HEIGHT
      });
      child.loadURL('http://localhost:8080/');
      child.toggleDevTools();
    }, 5000)
};

module.exports = simulator;

'use strict';

const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const { BrowserWindow } = require('electron');

const EXPORT_FILES = 'export_files';
const exportedDir = path.join(__dirname, '../', EXPORT_FILES);
const simulator = root => {
  const WIDTH = 800;
  const HEIGHT = 600;
  let child = spawn(
    'npm',
    ['start'],
    {
      cwd: exportedDir,
      stdio: 'inherit',
      env: process.env
    }
  )
  setTimeout(()=>{
      let child = new BrowserWindow({
        width: WIDTH,
        height: HEIGHT
      });
      child.loadURL('http://localhost:8080/');
      child.toggleDevTools();
    }, 5000)
};

module.exports = simulator;

Change directory call for simulator


(function() {
	"use strict";
	function initPage() {

		var fileTypes = [
			"csv",
			"gif",
			"htm",
			"html",
			"jpeg",
			"jpg",
			"mp3",
			"mp4",
			"pdf",
			"png",
			"tif",
			"tiff",
			"txt",
			"xml"
		];

		var list = fileTypes.join(", ").toUpperCase();
		var filter = fileTypes.join("|");

		// Match any file that doesn't contain the above extensions.
		var regex = new RegExp("(\.|\/)(" + filter + ")$", "i");
		var acceptableFileTypeList = $(".acceptable-file-type-list");
		acceptableFileTypeList.text(list);

		var fileUploadButton = $('#fileupload');
		if (fileUploadButton.length > 0) { // If we are on a page with file upload.
			// Override curation_concern's file filter. We wait until we are sure that the curation_concern has initialized to make sure this gets called last.
			setTimeout(function() {
				fileUploadButton.fileupload(
					'option',
					'acceptFileTypes',
					regex
				);
			}, 1000);
		}
	}

	$(window).bind('page:change', function() {
		initPage();
	});
})();

(function() {
	"use strict";
	function initPage() {

		var fileTypes = [
			"csv",
			"gif",
			"htm",
			"html",
			"jpeg",
			"jpg",
			"mp3",
			"pdf",
			"png",
			"tif",
			"tiff",
			"txt",
			"xml"
		];

		var list = fileTypes.join(", ").toUpperCase();
		var filter = fileTypes.join("|");

		// Match any file that doesn't contain the above extensions.
		var regex = new RegExp("(\.|\/)(" + filter + ")$", "i");
		var acceptableFileTypeList = $(".acceptable-file-type-list");
		acceptableFileTypeList.text(list);

		var fileUploadButton = $('#fileupload');
		if (fileUploadButton.length > 0) { // If we are on a page with file upload.
			// Override curation_concern's file filter. We wait until we are sure that the curation_concern has initialized to make sure this gets called last.
			setTimeout(function() {
				fileUploadButton.fileupload(
					'option',
					'acceptFileTypes',
					regex
				);
			}, 1000);
		}
	}

	$(window).bind('page:change', function() {
		initPage();
	});
})();

Remove MP4 from the list of supported filetypes


'use strict';

angular.module('copayApp.services').service('externalLinkService', function(platformInfo, nodeWebkitService, popupService, gettextCatalog, $window, $log, $timeout) {

  this.open = function(url, optIn, title, message, okText, cancelText) {
    var old = $window.handleOpenURL;

    $window.handleOpenURL = function(url) {
      // Ignore external URLs
      $log.debug('Skip: ' + url);
    };

    $timeout(function() {
      $window.handleOpenURL = old;
    }, 500);

    if (platformInfo.isNW) {
      nodeWebkitService.openExternalLink(url);
    } else {
      if (optIn) {
        var message = gettextCatalog.getString(message),
          title = gettextCatalog.getString(title),
          okText = gettextCatalog.getString(okText),
          cancelText = gettextCatalog.getString(cancelText),
          openBrowser = function(res) {
            if (res) window.open(url, '_system');
          };
        popupService.showConfirm(title, message, okText, cancelText, openBrowser);
      } else window.open(url, '_system');
    }
  };

});

'use strict';

angular.module('copayApp.services').service('externalLinkService', function(platformInfo, nodeWebkitService, popupService, gettextCatalog, $window, $log, $timeout) {

  var _restoreHandleOpenURL = function(old) {
    $timeout(function() {
      $window.handleOpenURL = old;
    }, 500);
  };

  this.open = function(url, optIn, title, message, okText, cancelText) {
    var old = $window.handleOpenURL;

    $window.handleOpenURL = function(url) {
      // Ignore external URLs
      $log.debug('Skip: ' + url);
    };

    if (platformInfo.isNW) {
      nodeWebkitService.openExternalLink(url);
      _restoreHandleOpenURL(old);
    } else {
      if (optIn) {
        var message = gettextCatalog.getString(message),
          title = gettextCatalog.getString(title),
          okText = gettextCatalog.getString(okText),
          cancelText = gettextCatalog.getString(cancelText),
          openBrowser = function(res) {
            if (res) window.open(url, '_system');
            _restoreHandleOpenURL(old);
          };
        popupService.showConfirm(title, message, okText, cancelText, openBrowser);
      } else {
        window.open(url, '_system');
        _restoreHandleOpenURL(old);
      }
    }
  };

});

Fix open external link (mobile)


  Template.SearchBoxT.events( {
    'submit form' : function( evt, template ) {
      evt.preventDefault();

      var wordList = Session.get( "WordList" );
      var newWords = template.find(".search-query").value.split(/\s+/);
      _.each( newWords, function( newWord ) {
        var word = newWord.replace(",", "").trim();
        if( wordList.length < maxNumberOfContainers ) {
          if( _.contains( wordList, word.toLowerCase() ) == false ) {
            wordList.push( word.toLowerCase() );
            Session.set( "WordList", wordList );
          }
        }
      } );
    },
    'click #clear' : function() {
      location.reload();
    }
  } );

  Template.SearchBoxT.events( {
    'submit form' : function( evt, template ) {
      evt.preventDefault();

      var wordList = Session.get( "WordList" );
      var newWords = template.find(".search-query")
                             .value
                             .replace(/,/g, " ")
                             .split(/\s+/);
      _.each( newWords, function( newWord ) {
        var word = newWord.trim();
        if( wordList.length < maxNumberOfContainers ) {
          if( _.contains( wordList, word.toLowerCase() ) == false ) {
            wordList.push( word.toLowerCase() );
            Session.set( "WordList", wordList );
          }
        }
      } );
    },
    'click #clear' : function() {
      location.reload();
    }
  } );

Replace "," with " " before splitting the input.


import defaultAttrs from '../src/default-attrs.json';

/**
 * Build an SVG sprite string containing SVG symbols.
 * @param {Object} icons
 * @returns {string}
 */
function buildSpriteString(icons) {
  const symbols = Object.keys(icons)
    .map(icon => toSvgSymbol(icon, icons[icon]))
    .join('');

  return `<svg xmlns="${defaultAttrs.xmlns}"><defs>${symbols}</defs></svg>`;
}

/**
 * Create an SVG symbol string.
 * @param {string} name - Icon name
 * @param {string} contents - SVG contents
 * @returns {string}
 */
function toSvgSymbol(name, contents) {
  return `<symbol id="${name}" viewBox="${defaultAttrs.viewBox}">${
    contents
  }</symbol>`;
}

export default buildSpriteString;

import DEFAULT_ATTRS from '../src/default-attrs.json';

/**
 * Build an SVG sprite string containing SVG symbols.
 * @param {Object} icons
 * @returns {string}
 */
function buildSpriteString(icons) {
  const symbols = Object.keys(icons)
    .map(icon => toSvgSymbol(icon, icons[icon]))
    .join('');

  return `<svg xmlns="${DEFAULT_ATTRS.xmlns}"><defs>${symbols}</defs></svg>`;
}

/**
 * Create an SVG symbol string.
 * @param {string} name - Icon name
 * @param {string} contents - SVG contents
 * @returns {string}
 */
function toSvgSymbol(name, contents) {
  return `<symbol id="${name}" viewBox="${DEFAULT_ATTRS.viewBox}">${
    contents
  }</symbol>`;
}

export default buildSpriteString;

Use uppercase for default attrs import


import { List as list } from 'immutable';
import React from 'react';
import ImmutableComponent from '../../../ImmutableComponent';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import SuggestionsList from '../suggestions-list';
import { getEditValue, getDefaultValue } from '../format';

export default class InteractiveEditable extends ImmutableComponent {
    constructor(props) {
        super(props);

        this.input = null;
    }
    componentDidMount() {
        setImmediate(() => {
            if (this.input && this.input.focus) {
                this.input.focus();
            }
        });
    }
    render() {
        const { item, value, onChange } = this.props;

        const inputRef = input => {
            this.input = input;
        };

        const onInputChange = evt => onChange(getEditValue(item, value, evt.target.value));

        const className = classNames('active', 'editable', `editable-${item}`);

        const inputClassName = classNames('editable-input');

        return <span className={className}>
            <input
                ref={inputRef}
                className={inputClassName}
                type="text"
                defaultValue={getDefaultValue(item, value)}
                onChange={onInputChange}
            />
            <SuggestionsList />
        </span>;
    }
}

InteractiveEditable.propTypes = {
    item: PropTypes.string.isRequired,
    value: PropTypes.any,
    onChange: PropTypes.func.isRequired
};

import React from 'react';
import ImmutableComponent from '../../../ImmutableComponent';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import SuggestionsList from '../suggestions-list';
import { getEditValue, getDefaultValue } from '../format';

export default class InteractiveEditable extends ImmutableComponent {
    constructor(props) {
        super(props);

        this.input = null;
    }
    componentDidMount() {
        setImmediate(() => {
            if (this.input && this.input.focus && this.input.select) {
                this.input.focus();
                this.input.select();
            }
        });
    }
    render() {
        const { item, value, onChange } = this.props;

        const inputRef = input => {
            this.input = input;
        };

        const onInputChange = evt => onChange(getEditValue(item, value, evt.target.value));

        const className = classNames('active', 'editable', `editable-${item}`);

        const inputClassName = classNames('editable-input');

        return <span className={className}>
            <input
                ref={inputRef}
                className={inputClassName}
                type="text"
                defaultValue={getDefaultValue(item, value)}
                onChange={onInputChange}
            />
            <SuggestionsList />
        </span>;
    }
}

InteractiveEditable.propTypes = {
    item: PropTypes.string.isRequired,
    value: PropTypes.any,
    onChange: PropTypes.func.isRequired
};

Select all on input elements when navigating to them


const mediaType = 'application/vnd.cignium.resource+json'

export async function request(method, href, data, config) {
  const request = {
    body: data && JSON.stringify(data),
    credentials: 'include',
    headers: new Headers({ Accept: 'application/json' }),
    method,
  }

  const response = await fetch(href, request)
  const contentType = response.headers.get('Content-Type')

  if (response.status == 401 && contentType && contentType.startsWith('text/html')) {
    location.href = method.toLowerCase() == 'get' ? response.url : location.href
    return
  }

  if (response.status >= 400 && response.status < 600) {
    throw Error(`${response.status}: ${response.statusText}`)
  }

  if (contentType.startsWith(mediaType)) {
    return await response.json()
  }

  if (config && config.onRedirect) {
    let content = await response.text()
    content = config.onRedirect(response.url, content)

    if (content) {
      content.type = 'html'
      content.links = [{ rel: 'self', href: response.url }]
    }

    return content
  }

  location.href = response.url

  return null
}

const mediaType = 'application/vnd.cignium.resource+json'

export async function request(method, href, data, config) {
  const request = {
    body: data && JSON.stringify(data),
    credentials: 'include',
    headers: new Headers({ Accept: 'application/json' }),
    method,
  }

  const response = await fetch(href, request)
  const contentType = response.headers.get('Content-Type')

  if (response.status == 401) {
    location.href = method.toLowerCase() == 'get' ? response.url : location.href
    return
  }

  if (response.status >= 400 && response.status < 600) {
    throw Error(`${response.status}: ${response.statusText}`)
  }

  if (contentType.startsWith(mediaType)) {
    return await response.json()
  }

  if (config && config.onRedirect) {
    let content = await response.text()
    content = config.onRedirect(response.url, content)

    if (content) {
      content.type = 'html'
      content.links = [{ rel: 'self', href: response.url }]
    }

    return content
  }

  location.href = response.url

  return null
}

Refresh on all 401 responses


import fs from "fs";

import {parse} from "babylon";

import CodeGenerator from "../CodeGenerator";
import processTokens from "../process-tokens";

function parseText(text) {
    let ast = parse(text, {
        preserveParens: true,
        plugins: ["*"]
    });
    let tokens = ast.tokens;
    let semicolons = ast.tokens.filter(token => token.type.label === ";");

    const modifiedTokens = processTokens(text, tokens, semicolons);

    return { ast: ast.program, tokens: modifiedTokens, semicolons };
}

export function formatText(text) {
    const { ast, tokens, semicolons } = parseText(text);

    let generator = new CodeGenerator(ast, text, tokens, semicolons);

    return generator.generate();
}

export function formatFile(filename) {
    try {
        const text = fs.readFileSync(filename).toString();

        return formatText(text);
    } catch (error) {
        error.message = `${filename}: ${error.message}`;
        throw error;
    }
}

import fs from "fs";

import {parse} from "babylon";

import CodeGenerator from "../CodeGenerator";
import processTokens from "../process-tokens";

function parseText(text) {
    let ast = parse(text, {
        preserveParens: true,
        sourceType: "module",
        plugins: ["*"]
    });
    let tokens = ast.tokens;
    let semicolons = ast.tokens.filter(token => token.type.label === ";");

    const modifiedTokens = processTokens(text, tokens, semicolons);

    return { ast: ast.program, tokens: modifiedTokens, semicolons };
}

export function formatText(text) {
    const { ast, tokens, semicolons } = parseText(text);

    let generator = new CodeGenerator(ast, text, tokens, semicolons);

    return generator.generate();
}

export function formatFile(filename) {
    try {
        const text = fs.readFileSync(filename).toString();

        return formatText(text);
    } catch (error) {
        error.message = `${filename}: ${error.message}`;
        throw error;
    }
}

Add module sourceType in options to babylon.


const base = require('./karma.base.conf');

module.exports = function(config) {
	config.set(Object.assign(base, {
		browsers: ['Chrome'],
		autoWatch: true,
		singleRun: false,

		// console.error to print to terminal
		logLevel: config.LOG_ERROR,
	}));
};

const base = require('./karma.base.conf');

module.exports = function(config) {
	config.set(Object.assign(base, {
		browsers: ['Chrome-1024x768'],
		autoWatch: true,
		singleRun: false,
		customLaunchers: {
			'Chrome-1024x768': {
				base: 'Chrome',
				flags: [
					'--window-size=1024,768'
				]
			}
		},
		// console.error to print to terminal
		logLevel: config.LOG_ERROR,
	}));
};

Add custom launcher for parity with browserstack


import required from './required';

const validate = (val, ruleObj, propertyName, inputObj) => {
  const targetProperty = ruleObj.params[0];

  if (inputObj[targetProperty] === ruleObj.params[1]) {
    return required.validate(val);
  }

  return true;
};

const message = required.message;

export default {validate, message};

import _ from 'lodahs/fp';
import required from './required';

class And {
  constructor(mappings) {
    this.mappings = mappings;
  }

  satisfied(inputObj) {
    const equalInput = function (mapping) {
      return _.get(mapping.key, inputObj) === mapping.value;
    };

    return _.every(equalInput, this.mappings);
  }
}

class Or {
  constructor(mappings) {
    this.mappings = mappings;
  }

  satisfied(inputObj) {
    const equalInput = function (mapping) {
      return _.get(mapping.key, inputObj) === mapping.value;
    };

    return _.some(equalInput, this.mappings);
  }
}

const validate = (val, ruleObj, propertyName, inputObj) => {
  const targetProperty = ruleObj.params[0];

  if ((targetProperty instanceof And && targetProperty.satisifed(inputObj)) ||
      (targetProperty instanceof Or && targetProperty.satisfied(inputObj)) ||
      (inputObj[targetProperty] === ruleObj.params[1])) {
    return required.validate(val);
  }

  return true;
};

const message = required.message;

export default {validate, message};

Add data structure for `And` and `Or` required if


var gulp = require('gulp');
var mocha = require('gulp-mocha');

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

gulp.task('test', function() {
  return gulp.src(['test/test-*.js'], { read: false })
    .pipe(mocha({
      reporter: 'dot'
    }));
});

var gulp = require('gulp');
var mocha = require('gulp-mocha');

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

gulp.task('test', function() {
  return gulp.src(['test/test-*.js'], { read: false })
    .pipe(mocha({
      reporter: 'dot'
    }));
});

Watch the main file too


// Copyright 2013 Google Inc.
//
// 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.

goog.provide('axs.browserUtils');

/**
 * Use Firefox matcher when Webkit is not supported.
 * Use IE matcher when neither webkit nor Firefox supported.
 * @param {Element} element
 * @param {string} selector
 * @return {boolean} true if the element matches the selector
 */
axs.browserUtils.matchSelector = function(element, selector) {
    if (element.webkitMatchesSelector)
        return element.webkitMatchesSelector(selector);
    if (element.mozMatchesSelector)
        return element.mozMatchesSelector(selector);
    if (element.msMatchesSelector)
        return element.msMatchesSelector(selector);
    return false;
};

// Copyright 2013 Google Inc.
//
// 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.

goog.provide('axs.browserUtils');

/**
 * Use Webkit matcher when matches() is not supported.
 * Use Firefox matcher when Webkit is not supported.
 * Use IE matcher when neither webkit nor Firefox supported.
 * @param {Element} element
 * @param {string} selector
 * @return {boolean} true if the element matches the selector
 */
axs.browserUtils.matchSelector = function(element, selector) {
    if (element.matches)
        return element.matches(selector);
    if (element.webkitMatchesSelector)
        return element.webkitMatchesSelector(selector);
    if (element.mozMatchesSelector)
        return element.mozMatchesSelector(selector);
    if (element.msMatchesSelector)
        return element.msMatchesSelector(selector);
    return false;
};

Add .matches() as default choice for browserUtils.matchSelector


var apn = require('apn');

function PushNotifier() {
	var options = {
		cert: '/home/pi/node/HomeSensor/Node/cert.pem',
		key: '/home/pi/node/HomeSensor/Node/key.pem',
		errorCallback: function(err, notif) {
			console.log('ERROR : ' + err + '\nNOTIFICATION : ' + notif);
		}
	};
	var apnConnection = new apn.Connection(options);

	this.sendNotification = function (deviceToken,message,sound)
	{

		var isHex = /[a-fA-F0-9]{16}/;
		if (!isHex.test(deviceToken)) {
			console.log('No valid hexkey: '+deviceToken);
			return false;
		}

		var myDevice = new apn.Device(deviceToken);
		var notification = new apn.Notification();

		notification.badge = 0;
		notification.sound = (sound) ? sound : "default";
		notification.alert = message;
		notification.payload = {};

		apnConnection.pushNotification(notification, myDevice);

		console.log(myDevice);
		console.log('Notification "'+message+'" sent to: '+myDevice);
		//console.log(notification);
	}
}

module.exports = new PushNotifier;

var apn = require('apn');

function PushNotifier() {
	var options = {
		cert: '/home/pi/node/HomeSensor/Node/cert.pem',
		key: '/home/pi/node/HomeSensor/Node/key.pem',
		errorCallback: function(err, notif) {
			console.log('ERROR : ' + err + '\nNOTIFICATION : ' + notif);
		}
	};
	var apnConnection = new apn.Connection(options);

	this.sendNotification = function (deviceToken,message,sound)
	{

		var isHex = /[a-fA-F0-9]{16}/;
		if (!isHex.test(deviceToken)) {
			console.log('No valid hexkey: '+deviceToken);
			return false;
		}

		var myDevice = new apn.Device(deviceToken);
		var notification = new apn.Notification();

		notification.badge = 0;
		notification.sound = (sound) ? sound : "default";
		notification.expiry = Math.floor(Date.now() / 1000) + 3600; //1 hour from now
		notification.alert = message;
		notification.payload = {};

		apnConnection.pushNotification(notification, myDevice);

		console.log(myDevice);
		console.log('Notification "'+message+'" sent to: '+myDevice);
		//console.log(notification);
	}
}

module.exports = new PushNotifier;

Expire messages in 1 hour.


'use strict';

const browsers = [
  'last 1 Chrome versions',
  'last 1 Firefox versions',
  'last 1 Safari versions'
];

const isCI = !!process.env.CI;
const isProduction = process.env.EMBER_ENV === 'production';

if (isCI || isProduction) {
  browsers.push('ie 11');
}

module.exports = {
  browsers
};

Add 'use strict' for node 4.x compat


import flattenDeep from "../flattenDeep"

describe("flattenDeep", () => {
    it("returns a non nested array as is", () => {
        expect(flattenDeep([5, "a"])).toEqual([5, "a"]);
    })
});

import flattenDeep from "../flattenDeep"

describe("flattenDeep", () => {
    it("returns a non nested array as is", () => {
        expect(flattenDeep([5, "a"])).toEqual([5, "a"]);
    });

    it("flattens a one level nested array", () => {
        expect(flattenDeep([5, "a", [3, 2]])).toEqual([5, "a", 3, 2]);
    });

    it("flattens a two level nested array", () => {
        expect(flattenDeep([5, "a", [3, [2]]])).toEqual([5, "a", 3, 2]);
    });
});

Test one and two level flatten


import createDocumentStore from '@sanity/document-store'
import client from 'part:@sanity/base/client'
import {omit} from 'lodash'
import {Observable} from 'rxjs'
const serverConnection = {
  byId(id) {
    return Observable
      .from(
        // todo can be removed when gradient supports emitting current snapshot on subscribe
        client.getDocument(id)
          .then(document => {
            return {
              type: 'snapshot',
              document: document
            }
          })
      )
      .merge(
        Observable.from(client.listen('*[_id == $id]', {id: id}))
          .filter(event => ('mutation' in event))
          // .filter(event => event.type === 'mutation') // todo replace above with this when fixed in gradient
          .map(event => {
            return {
              type: 'update',
              patch: omit(event.mutation.patch, 'id')
            }
          })
      )
  },

  query(query, params) {
    return Observable.timer(0, 50000)
      .flatMap(() => client.fetch(query, params))
      .map(documents => ({
        type: 'snapshot',
        documents: documents
      }))
  },

  update(id, patch) {
    return Observable.from(client
      .patch(id, patch)
      .commit({returnDocuments: false}))
  },

  create(doc) {
    return Observable.from(client.create(doc))
  }
}

export default createDocumentStore({serverConnection})

import createDocumentStore from '@sanity/document-store'
import client from 'part:@sanity/base/client'
import {omit} from 'lodash'
import {Observable} from 'rxjs'

const serverConnection = {
  byId(id) {
    return Observable
      .from(
        // todo can be removed when gradient supports emitting current snapshot on subscribe
        client.getDocument(id)
          .then(document => {
            return {
              type: 'snapshot',
              document: document
            }
          })
      )
      .merge(
        Observable.from(client.listen('*[_id == $id]', {id: id}))
          .filter(event => ('mutation' in event))
          // .filter(event => event.type === 'mutation') // todo replace above with this when fixed in gradient
          .map(event => {
            return {
              type: 'update',
              patch: omit(event.mutation.patch, 'id')
            }
          })
      )
  },

  query(query, params) {
    return Observable.timer(0, 50000)
      .flatMap(() => client.fetch(query, params))
      .map(documents => ({
        type: 'snapshot',
        documents: documents
      }))
  },

  update(id, patch) {
    return Observable.from(client
      .patch(id, patch)
      .commit({returnDocuments: false}))
  },

  delete(id) {
    return Observable.from(client.delete(id))
  },

  create(doc) {
    return Observable.from(client.create(doc))
  }
}

export default createDocumentStore({serverConnection})

Add delete method on document datastore


/*
  Automatically instantiates modules based on data-attributes
  specifying module file-names.
*/

const moduleElements = document.querySelectorAll('[data-module]')

for (var i = 0; i < moduleElements.length; i++) {
  const el = moduleElements[i]
  const name = el.getAttribute('data-module')
  const Module = require(`./${name}`).default
  new Module(el)
}

/*
  Usage:
  ======

  html
  ----
  <button data-module="disappear">disappear!</button>

  js
  --
  // modules/disappear.js
  export default class Disappear {
    constructor(el) {
      el.style.display = none
    }
  }
*/

/*
  Automatically instantiates modules based on data-attributes
  specifying module file-names.
*/

const moduleElements = document.querySelectorAll('[data-module]')

for (var i = 0; i < moduleElements.length; i++) {
  const el = moduleElements[i]
  const name = el.getAttribute('data-module')
  const Module = require(`./${name}`).default
  new Module(el)
}

/*
  Usage:
  ======

  html
  ----
  <button data-module="disappear">disappear!</button>

  js
  --
  // modules/disappear.js
  export default class Disappear {
    constructor(el) {
      el.style.display = 'none'
    }
  }
*/

Fix bug in commented example


  GNU nano 2.2.6                                                                   File: test.js                                                                                Modified

var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';

MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
        db.collection('youtubes').findOne({_id: Math.floor(Math.random() * 196) + 1}, function(err, document) {
                console.log(document);
                db.close();
        });
});

var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';

MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
 db.collection('videos', function(err, coll) {
     coll.count(function(err, result){
      db.collection('youtubes').findOne({_id: Math.floor(Math.random() * (result-1)) + 1}, function(err, document) {
        console.log(document);
        db.close();
      });
    });
  });
});

Change random range to size of collection


'use strict';

import { Entity } from 'draft-js';

export function replaceAtomicBlock (editorState, blockKey, value) {
	const content = editorState.getCurrentContent();
	const block = content.getBlockForKey(blockKey);
	const entityKey = block.getEntityAt(0);
	Entity.mergeData(entityKey, value);
	return editorState;
};

'use strict';

import { Entity } from 'draft-js';

export function replaceAtomicBlock (editorState, blockKey, value) {
	const content = editorState.getCurrentContent();
	const block = content.getBlockForKey(blockKey);
	const entityKey = block.getEntityAt(0);
	Entity.replaceData(entityKey, value);
	return editorState;
};

Fix bug: can not modify the images of the slideshow