/**
 * Default user preferences. End-users can change these parameters by editing config.json
 * @param {number} version - Scheme version. (Not application version)
 */
const defaultPreferences = {
  version: 1,
  teams: [],
  showTrayIcon: false,
  trayIconTheme: 'light',
  minimizeToTray: false,
  notifications: {
    flashWindow: 0,
    bounceIcon: false,
    bounceIconType: 'informational',
  },
  showUnreadBadge: true,
  useSpellChecker: true,
  enableHardwareAcceleration: false,
};

export default defaultPreferences;

/**
 * Default user preferences. End-users can change these parameters by editing config.json
 * @param {number} version - Scheme version. (Not application version)
 */
const defaultPreferences = {
  version: 1,
  teams: [],
  showTrayIcon: false,
  trayIconTheme: 'light',
  minimizeToTray: false,
  notifications: {
    flashWindow: 0,
    bounceIcon: false,
    bounceIconType: 'informational',
  },
  showUnreadBadge: true,
  useSpellChecker: true,
  enableHardwareAcceleration: true,
};

export default defaultPreferences;

Enable GPU hardware acceleration by default


import ListFormRoute from 'ember-flexberry/routes/list-form';

export default ListFormRoute.extend({
  /**
    Name of model projection to be used as record's properties limitation.

    @property modelProjection
    @type String
    @default 'SuggestionL'
   */
  modelProjection: 'SuggestionL',

  /**
  developerUserSettings.
  {
  <componentName>: {
    <settingName>: {
        colsOrder: [ { propName :<colName>, hide: true|false }, ... ],
        sorting: [{ propName: <colName>, direction: "asc"|"desc" }, ... ],
        colsWidths: [ <colName>:<colWidth>, ... ],
      },
      ...
    },
    ...
  }
  For default userSetting use empty name ('').
  <componentName> may contain any of properties: colsOrder, sorting, colsWidth or being empty.

  @property developerUserSettings
  @type Object
  @default {}
  */
  developerUserSettings: { FOLVSettingExampleObjectListView: { } },

  /**
    Name of model to be used as list's records types.

    @property modelName
    @type String
    @default 'ember-flexberry-dummy-suggestion'
   */
  modelName: 'ember-flexberry-dummy-suggestion'
});

import ListFormRoute from 'ember-flexberry/routes/list-form';

export default ListFormRoute.extend({
  /**
    Name of model projection to be used as record's properties limitation.

    @property modelProjection
    @type String
    @default 'SuggestionL'
   */
  modelProjection: 'SuggestionL',

  /**
  developerUserSettings.
  {
  <componentName>: {
    <settingName>: {
        colsOrder: [ { propName :<colName>, hide: true|false }, ... ],
        sorting: [{ propName: <colName>, direction: "asc"|"desc" }, ... ],
        colsWidths: [ <colName>:<colWidth>, ... ],
      },
      ...
    },
    ...
  }
  For default userSetting use empty name ('').
  <componentName> may contain any of properties: colsOrder, sorting, colsWidth or being empty.

  @property developerUserSettings
  @type Object
  @default {}
  */
  developerUserSettings: { FOLVSettingsExampleObjectListView: { } },

  /**
    Name of model to be used as list's records types.

    @property modelName
    @type String
    @default 'ember-flexberry-dummy-suggestion'
   */
  modelName: 'ember-flexberry-dummy-suggestion'
});

Fix sorting on FOLV settings example


'use strict';

let content = require('./content.js');

function validateInputs(err, obj) {

    err.items = [];

    let errCount = 0;

    if (obj.forename && !isString(obj.forename)) {
        err.items[errCount++] = {forename: 'Correct the forename'};
    }
    if (obj.forename2 && !isString(obj.forename2)) {
        err.items[errCount++] = {forename2: 'Correct the middle name'};
    }
    if (obj.surname && !isString(obj.surname)) {
        err.items[errCount++] = {surname: 'Correct the surname'};
    }

    return errCount;
}

module.exports = {

    validate: function(obj, callback) {

        let err = {
            title: content.errMsg.CANNOT_SUBMIT,
            items: [{forename: 'Enter forename'}, {forename2: 'Enter middle name'}, {surname: 'Enter surname'}],
            desc: content.errMsg.ATLEAST_ONE_REQUIRED
        };

        if (!obj.forename && !obj.forename2 && !obj.surname) {
            return callback(err);
        }

        let errCount = validateInputs(err, obj);

        if (errCount > 0) {
            return callback(err);
        }

        return callback(null);
    }
};

function isString(v) {
    return /^[A-Za-z%_]+$/.test(v);
}

'use strict';

let content = require('./content.js');

function validateInputs(err, obj) {

    err.items = [];

    let errCount = 0;

    if (obj.forename && !isString(obj.forename)) {
        err.items[errCount++] = {forename: 'Correct the forename'};
    }
    if (obj.forename2 && !isString(obj.forename2)) {
        err.items[errCount++] = {forename2: 'Correct the middle name'};
    }
    if (obj.surname && !isString(obj.surname)) {
        err.items[errCount++] = {surname: 'Correct the surname'};
    }

    return errCount;
}

module.exports = {

    validate: function(obj, callback) {

        let err = {
            title: content.errMsg.CANNOT_SUBMIT,
            items: [{forename: 'Enter forename'}, {forename2: 'Enter middle name'}, {surname: 'Enter surname'}],
            desc: content.errMsg.ATLEAST_ONE_REQUIRED
        };

        if (!obj.forename && !obj.forename2 && !obj.surname) {
            return callback(err);
        }

        let errCount = validateInputs(err, obj);

        if (errCount > 0) {
            return callback(err);
        }

        return callback(null);
    }
};

function isString(v) {
    return /^[\sA-Za-z%_'-]+$/.test(v);
}

Allow space,dash,apostrophe in name searches


module.exports = function(config){
  config.set({
    basePath : '../../',

    files : [
      'bower_components/jquery/jquery.js',
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'dist/nga11y.min.js',
      'test/*.js'
    ],

    exclude : [
      'bower_components/angular/*.min.js'
    ],

    autoWatch : true,

    frameworks: [ 'jasmine'],

    browsers : ['Chrome'],

    reporters: ['spec'],

    plugins : [
            'karma-chrome-launcher',
            'karma-phantomjs-launcher',
            'karma-firefox-launcher',
            'karma-script-launcher',
            'karma-spec-reporter',
            'karma-jasmine'
            ]
  });
};

module.exports = function(config){
  config.set({
    basePath : '../../',

    files : [
      'bower_components/jquery/jquery.js',
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'dist/nga11y.min.js',
      'test/*.js'
    ],

    exclude : [
      'bower_components/angular/*.min.js'
    ],

    autoWatch : true,

    frameworks: [ 'jasmine'],

    browsers : [ 'Chrome', 'PhantomJS' ],

    reporters: [ 'spec' ],

    plugins : [
            'karma-chrome-launcher',
            'karma-phantomjs-launcher',
            'karma-firefox-launcher',
            'karma-script-launcher',
            'karma-spec-reporter',
            'karma-jasmine'
            ]
  });
};

Add PhantomJS to the standard developer unit tests


var expect = require('chai').expect;
var io = require('socket.io-client');
var localServerUri = 'http://127.0.0.1:3000/';
var connection;

describe('Socket Server', function() {

  it('should receive a new socket connection', function(done) {
    connection = io(localServerUri);
    connection.on('connect', function() {
      done();
    });
  });

  it('should authenticate the connection', function(done) {
    var userObject = {userToken: 'ABCDEFG'};
    connection.emit('init', userObject);
    connection.on('init', function() {
      done();
    });
  });
});

var expect = require('chai').expect;
var io = require('socket.io-client');
var models = require('../server/db/models');
var localServerUri = 'http://127.0.0.1:3000/';
var testUser = {userToken: 'ABCDEFG'};
var testMsg = {x: 100, y: 100, z: 100, message: 'hello database!', userToken: testUser.userToken};
var testComment = {x: 101, y: 101, z: 101, commentString: 'hello database comment!', userToken: testUser.userToken};
var testVote = {userToken: testUser.userToken};
var connection;

describe('Socket Server', function() {

  before(function(done) {
    models.createUser(testUser.userToken)
    .then(function(data) {
      testVote.messageId = data.insertId;
      done();
    });
  });

  after(function(done) {
    models.deleteRow('marks', ['x', testMsg.x])
    .then(function() {
      return models.deleteRow('marks', ['x', testComment.x]);
    }).then(function() {
      return models.deleteRow('votes', ['userToken', testVote.userToken]);
    }).then(function() {
      return models.deleteRow('comments', ['commentString', testComment.commentString]);
    }).then(function() {
      return models.deleteRow('messages', ['messageString', testMsg.message]);
    }).then(function() {
      return models.deleteRow('users', ['token', testUser.userToken]);
    }).then(function() {
      done();
    });
  });

  it('should receive a new socket connection', function(done) {
    connection = io(localServerUri);
    connection.on('connect', function() {
      done();
    });
  });

  it('should authenticate the connection', function(done) {
    connection.emit('init', testUser);
    connection.on('init', function() {
      done();
    });
  });

});

Add before and after hooks for socket testing


/**
 * GET /
 * Home page.
 */
import { match } from 'react-router';
import Application from '../../application/HelloWorld';

exports.home = (req, res) => {
  match({
    routes: Application.Routes,
    location: req.url,
  }, (err, redirect, routerProps) => {
    res.render('default', {
      Application,
      payload: {
        title: 'My Application',
        description: 'This is an example.',
        routerProps, // Pass Props to RouterContext.
      },
    });
  });
};

/**
 * GET /
 * Home page.
 */
import { match } from 'react-router';
import Application from '../../application/HelloWorld';

export default (req, res) => {
  match({
    routes: Application.Routes,
    location: req.url,
  }, (err, redirect, routerProps) => {
    res.render('default', {
      Application,
      payload: {
        title: 'My Application',
        description: 'This is an example.',
        routerProps, // Pass Props to RouterContext.
      },
    });
  });
};

Use ES6 way of exporting default.


const sanitize = (name) => {
  return name
    .replace(':', '')
}

export default {
  set (state, { key, value }) {
    state.info[sanitize(key)] = value
  },
  addEps (state, { name, data }) {
    state.info[name].episodesInfo = data
  },
  addEpsLinks (state, { name, data }) {
    state.info[name].episodesLinks = data
  },
  showModal (state, bool) {
    state.modal.show = bool
  },
  setTerm (state, value) {
    state.modal.term = value
  },
  setRemote (state, bool) {
    state.modal.isRemote = bool
  }
}

const sanitize = (name) => {
  return name
    .replace(':', '')
}

export default {
  set (state, { key, value }) {
    state.info[sanitize(key)] = value
  },
  addEps (state, { name, data }) {
    state.info[sanitize(name)].episodesInfo = data
  },
  addEpsLinks (state, { name, data }) {
    state.info[name].episodesLinks = data
  },
  showModal (state, bool) {
    state.modal.show = bool
  },
  setTerm (state, value) {
    state.modal.term = value
  },
  setRemote (state, bool) {
    state.modal.isRemote = bool
  }
}

Fix bug where info name was not sanitzed before comitting


(function () {

    new SliderBarr({
        el    : $('#slider'),
        value : 15,
        step  : 1
    });

    new SliderBarr({
        el    : $('#sliderTwo'),
        value : 75,
        step  : 10
    });

    var sliderThree = new SliderBarr({
        el     : $('#sliderThree'),
        value  : 50,
        step   : 1,
        labels : true
    });

}).call(this);

(function () {

    new SliderBarr({
        el    : $('#slider'),
        value : 15,
        step  : 1
    });

    new SliderBarr({
        el    : $('#sliderTwo'),
        value : 75,
        step  : 10
    });

    new SliderBarr({
        el     : $('#sliderThree'),
        value  : 50,
        step   : 1,
        labels : true
    });

}).call(this);

Remove unnecessary things from slider example.


/*
    The Company module exposes functionality needed in the company section
    of the dashboard.
*/

var Inventory = (function ($, tools) {

    // Perform self check, display error if missing deps
    var performSelfCheck = function () {
        var errors = false
        if ($ == undefined) {
            console.error('jQuery missing!')
            errors = !errors
        }
        if (tools == undefined) {
            console.error('Dashboard tools missing!')
            errors = !errors
        }
        if (errors) return false
        return true
    }

    return {

        // Bind them buttons and other initial functionality here
        init: function () {

            if (!performSelfCheck()) return

            $('#inventory_item_list').tablesorter()

        }

    }

})(jQuery, Dashboard.tools)

$(document).ready(function () {
    Inventory.init()
})

/*
    The Company module exposes functionality needed in the company section
    of the dashboard.
*/

var Inventory = (function ($, tools) {

    // Perform self check, display error if missing deps
    var performSelfCheck = function () {
        var errors = false
        if ($ == undefined) {
            console.error('jQuery missing!')
            errors = true
        }
        if (tools == undefined) {
            console.error('Dashboard tools missing!')
            errors = true
        }
        if (errors) return false
        return true
    }

    return {

        // Bind them buttons and other initial functionality here
        init: function () {

            if (!performSelfCheck()) return

            $('#inventory_item_list').tablesorter()

        }

    }

})(jQuery, Dashboard.tools)

$(document).ready(function () {
    Inventory.init()
})

Fix potentially broken selfcheck if two errors occur


import React, { Component, PropTypes } from 'react';
import styles from './Input.css';

class Input extends Component {
  constructor(props) {
    super(props);
    this.submitInput = this.submitInput.bind(this);
  }

  submitInput(event) {
    const text = event.target.value;
    if (event.which === 13 && text.trim() !== '') {
      this.props.addTodo(text);
    }
  }

  render() {
    return (
      <div className={styles.input}>
        <input
          type="text"
          placeholder="What needs to be done?"
          onKeyDown={this.submitInput}
        />
      </div>
    );
  }
}

Input.propTypes = {
  addTodo: PropTypes.func.isRequired
};

export default Input;

import React, { Component, PropTypes } from 'react';
import styles from './Input.css';

class Input extends Component {
  constructor(props) {
    super(props);
    this.state = { text: '' };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    const text = e.target.value;
    if (e.which === 13 && text.trim() !== '') {
      this.props.addTodo(text);
      this.setState({ text: '' });
    }
  }

  handleChange(e) {
    this.setState({ text: e.target.value });
  }

  render() {
    return (
      <div className={styles.input}>
        <input
          type="text"
          placeholder="What needs to be done?"
          value={this.state.text}
          onChange={this.handleChange}
          onKeyDown={this.handleSubmit}
        />
      </div>
    );
  }
}

Input.propTypes = {
  addTodo: PropTypes.func.isRequired
};

export default Input;

Implement Input component state for controlling current text input value


import { expect, } from 'chai'

import * as JobActions from '../../actions/JobActions'
import * as JobActionTypes from '../../constants/JobActionTypes'
import * as JobApiActionTypes from '../../constants/JobApiActionTypes'
import * as JobApiActions from '../../actions/JobApiActions'
import * as Sagas from '../sagas'

describe('asdsad', () => {
  it('asdasd', () => {

  })
})

import { expect, } from 'chai'
import { take, put, call, fork, select, } from 'redux-saga/effects'

import * as JobActions from '../../actions/JobActions'
import * as JobActionTypes from '../../constants/JobActionTypes'
import * as JobApiActions from '../../actions/JobApiActions'
import * as JobApiActionTypes from '../../constants/JobApiActionTypes'
import * as JobSortStrategies from '../../constants/JobSortStrategies'
import * as API from '../api'
import rootSaga, * as sagas from '../sagas'

describe('sagas', () => {
  describe('putOpenErrorSnackbarAction', () => {
    it(`should put ${JobActionTypes.OPEN_ERROR_SNACKBAR} with { message, error }`, () => {
      const [message, error] = ['error occurred', new Error('error01')]
      const saga = sagas.putOpenErrorSnackbarAction(message, error)

      expect(saga.next().value).to.deep.equal(
        put(JobActions.openErrorSnackbar({ message, error, }))
      )
    })
  })

  describe('putOpenInfoSnackbarAction', () => {
    it(`should put ${JobActionTypes.OPEN_INFO_SNACKBAR} with { message }`, () => {
      const [message, error] = ['error occurred', new Error('error01')]
      const saga = sagas.putOpenInfoSnackbarAction(message)

      expect(saga.next().value).to.deep.equal(
        put(JobActions.openInfoSnackbar({ message, }))
      )
    })
  })

  describe('callFetchJobs', () => {
    it(`should
        - get jobs from server
        - put ${JobApiActionTypes.FETCH_JOBS.SUCCEEDED} with { jobs }
        - put ${JobActionTypes.SORT} with { strategy: ${JobSortStrategies.INITIAL} }
        `, () => {
      const jobs = [ { id: 'job1', }, { id: 'job2', }]
      const saga = sagas.callFetchJobs()

      expect(saga.next().value).to.deep.equal(
        call(API.fetchJobs)
      )

      expect(saga.next(jobs).value).to.deep.equal(
        put(JobApiActions.fetchJobsSucceeded({ jobs, }))
      )

      expect(saga.next().value).to.deep.equal(
        put(JobActions.sortJob({ strategy: JobSortStrategies.INITIAL, }))
      )
    })
  })
})

describe('root saga', () => {
  it('should', () => {

  })
})

Write tests for saga helpers


/*!
 * Copyright 2017 Pentaho Corporation. All rights reserved.
 *
 * 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.
 */

define([
  'angular'
], function(angular) {
  focus.inject = ['$timeout'];

  /**
   * @param {Function} $timeout - Angular wrapper for window.setTimeout.
   * @return {{restrict: string, scope: {model: string}, link: link}} - Focus directive
   */
  function focus($timeout) {
    return {
      restrict: 'AE',
      scope: {model: '=ngModel'},
      link: function(scope, element, attrs) {
        var watch = scope.$watch("model", function(value) {
          $timeout(function() {
            element[0].focus();
            element[0].select();
            element[0].setSelectionRange(0, value.length);
            $timeout(function() {
              watch();
            }, 500);
          });
        });
      }
    };
  }

  return {
    name: "focus",
    options: ['$timeout', focus]
  };
});

/*!
 * Copyright 2017 Pentaho Corporation. All rights reserved.
 *
 * 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.
 */

define([
  'angular'
], function(angular) {
  focus.inject = ['$timeout'];

  /**
   * @param {Function} $timeout - Angular wrapper for window.setTimeout.
   * @return {{restrict: string, scope: {model: string}, link: link}} - Focus directive
   */
  function focus($timeout) {
    return {
      restrict: 'A',
      scope: {model: '<ngModel'},
      link: function(scope, element, attrs) {
        var watch = scope.$watch("model", function(value) {
          if (value === "") {
            return;
          }
          $timeout(function() {
            element[0].focus();
            element[0].select();
            element[0].setSelectionRange(0, value.length);
            watch();
          });
        });
      }
    };
  }

  return {
    name: "focus",
    options: ['$timeout', focus]
  };
});

Check for empty values before setting selection


// devtools-detect
// by Sindre Sorhus
// MIT License
(function (window) {
	/*global CustomEvent */
	'use strict';
	var devtools = window.devtools = { open: false };
	var threshold = 150;
	var emitEvent = function (state) {
		window.dispatchEvent(new CustomEvent('devtoolschange', {
			detail: {
				open: state
			}
		}));
	};

	setInterval(function () {
		if (window.outerWidth - window.innerWidth > threshold ||
			window.outerHeight - window.innerHeight > threshold) {
			if (!devtools.open) {
				emitEvent(true);
			}
			devtools.open = true;
		} else {
			if (devtools.open) {
				emitEvent(false);
			}
			devtools.open = false;
		}
	}, 500);
})(window);

// devtools-detect
// by Sindre Sorhus
// MIT License
(function (window) {
	/*global CustomEvent */
	'use strict';
	var devtools = window.devtools = { open: false };
	var threshold = 160;
	var emitEvent = function (state) {
		window.dispatchEvent(new CustomEvent('devtoolschange', {
			detail: {
				open: state
			}
		}));
	};

	setInterval(function () {
		if (window.outerWidth - window.innerWidth > threshold ||
			window.outerHeight - window.innerHeight > threshold) {
			if (!devtools.open) {
				emitEvent(true);
			}
			devtools.open = true;
		} else {
			if (devtools.open) {
				emitEvent(false);
			}
			devtools.open = false;
		}
	}, 500);
})(window);

Increase threshold to account for Chrome downloadbar


/*
*   Blaze object. Inherits GameObject.
 */
function Blaze(coordinate) {
    console.log("Blaze constructor.")
    GameObject.call(this, coordinate);
}

Blaze.prototype = new GameObject();

Blaze.prototype.constructor = Blaze;

/*
*   Prints Blaze's properties on the console.
 */
Blaze.prototype.toString = function () {
    var result = "Blaze:\n" + GameObject.prototype.toString.call(this);
    return result;
}

	// var GlobalConsts = require('GlobalConsts.js');

	var _maxBulletsCount = 0,
		_currentBulletsCount = 0,
		_reloadingTime = 0;

	/*
	 *   Blaze object. Inherits GameObject.
	 */
	function Blaze(coordinate) {
		console.log("Blaze constructor.")
		GameObject.call(this, coordinate);

		// _maxBulletsCount = GlobalConsts.PLAYER_BULLETS_COUNT;
		_maxBulletsCount = 3;
		_currentBulletsCount = _maxBulletsCount;
		// _reloadingTime = GlobalConsts.PLAYER_CLIP_REALOADING_TIME;
		_reloadingTime = 3000; //ms
	}

	Blaze.prototype = new GameObject();

	Blaze.prototype.constructor = Blaze;

	Blaze.prototype.getBulletsCount = function() {
		return _currentBulletsCount;
	}

	Blaze.prototype.shoot = function() {
		_currentBulletsCount--;
		if (_currentBulletsCount === 0) {
			this.reload();
		}

		//here to check if hit something?
	}

	Blaze.prototype.reload = function() {
		//here to set timeout?
		_currentBulletsCount = _maxBulletsCount;
	}

	/*
	 *   Prints Blaze's properties on the console.
	 */
	Blaze.prototype.toString = function() {
		var result = "Blaze:\n" + GameObject.prototype.toString.call(this);
		return result;
	}

Add methods to player class


var matrixcs = require("./lib/matrix");
matrixcs.request(require("browser-request"));

// if our browser (appears to) support indexeddb, use an indexeddb crypto store.
if (global.indexedDB) {
    matrixcs.setCryptoStoreFactory(
        function() {
            return new matrixcs.IndexedDBCryptoStore(
                global.indexedDB, "matrix-js-sdk:crypto"
            );
        }
    );
}

module.exports = matrixcs; // keep export for browserify package deps
global.matrixcs = matrixcs;

var matrixcs = require("./lib/matrix");
matrixcs.request(require("browser-request"));

// just *accessing* indexedDB throws an exception in firefox with
// indexeddb disabled.
let indexedDB;
try {
    indexedDB = global.indexedDB;
} catch(e) {}

// if our browser (appears to) support indexeddb, use an indexeddb crypto store.
if (indexedDB) {
    matrixcs.setCryptoStoreFactory(
        function() {
            return new matrixcs.IndexedDBCryptoStore(
                indexedDB, "matrix-js-sdk:crypto"
            );
        }
    );
}

module.exports = matrixcs; // keep export for browserify package deps
global.matrixcs = matrixcs;

Fix load failure in firefox when indexedDB is disabled


'use strict';

var gulp = require('gulp');
var stylus = require('gulp-stylus');
var nib = require('nib');
var ignore = require('gulp-ignore');
var config = require('../util/config');
var postcss = require('gulp-postcss');

var glob = config.path.source + 'style/**/*.styl';

gulp.task('stylus', function () {
  return gulp.src(glob, {base: config.path.source})
    .pipe(stylus({use: [nib()]}))
    .pipe(ignore('**/_*.css'))
    .pipe(gulp.dest(config.path.dest));
});

exports.glob = glob;

'use strict';

var gulp = require('gulp');
var stylus = require('gulp-stylus');
var nib = require('nib');
var ignore = require('gulp-ignore');
var config = require('../util/config');

var glob = config.path.source + 'style/**/*.styl';

gulp.task('stylus', function () {
  return gulp.src(glob, {base: config.path.source})
    .pipe(stylus({use: [nib()]}))
    .pipe(ignore('**/_*.css'))
    .pipe(gulp.dest(config.path.dest));
});

exports.glob = glob;

Remove unused require for gulp-postcss.


javascript:function fx(str){return encodeURIComponent(str).replace(/[!'()*]/g, function(c){return '%' + c.charCodeAt(0).toString(16);});};var captureLink=function(){var s=window.getSelection().toString(),l=window.location.href,t=document.title, d=document.querySelector('meta[name=description]'), k=document.querySelector('meta[name=keywords]'),p='capture';if(d){d=d.attributes.content.value.toString()};if(k){k.attributes.content.value.toString()};var uri='http://localhost:9998/?'+'p='+p+'&l='+fx(l)+'&t='+fx(t)+'&s='+fx("description: "+d+"\n\n" + "selection: " + s + "\n\n");window.location=uri;return uri;};captureLink();

Add extra gunk to payload


this.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});

this.addEventListener('fetch', function(event) {
  var response;
  var cachedResponse = caches.match(event.request).catch(function() {
    return fetch(event.request);
  }).then(function(r) {
    response = r;
    caches.open('v1').then(function(cache) {
      cache.put(event.request, response);
    });
    return response.clone();
  }).catch(function() {
    return caches.match('/sw-test/gallery/myLittleVader.jpg');
  });
});

this.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});

this.addEventListener('fetch', function(event) {
  var response;
  event.respondWith(caches.match(event.request).catch(function() {
    return fetch(event.request);
  }).then(function(r) {
    response = r;
    caches.open('v1').then(function(cache) {
      cache.put(event.request, response);
    });
    return response.clone();
  }).catch(function() {
    return caches.match('/sw-test/gallery/myLittleVader.jpg');
  }));
});

Call e.respondWith() in fetch event handler.


import cookie from 'react-cookie';

import { Meteor } from 'meteor/meteor';

import { getRenderContext } from './render_context.js';

function setToken(loginToken, expires) {
  if (loginToken && expires !== -1) {
    cookie.save('meteor_login_token', loginToken, {
      path: '/',
      expires,
    });
  } else {
    cookie.remove('meteor_login_token', {
      path: '/',
    });
  }
}

function resetToken() {
  const context = getRenderContext();
  const loginToken = global.localStorage['Meteor.loginToken'];
  const loginTokenExpires = new Date(global.localStorage['Meteor.loginTokenExpires']);

  if (loginToken) {
    setToken(loginToken, loginTokenExpires);
  } else {
    setToken(null, -1);
  }

  context.loginToken = loginToken;
}

Meteor.startup(() => {
  resetToken();
});

const originalSetItem = Meteor._localStorage.setItem;
Meteor._localStorage.setItem = function setItem(key, value) {
  if (key === 'Meteor.loginToken') {
    Meteor.defer(resetToken);
  }
  originalSetItem.call(Meteor._localStorage, key, value);
};

const originalRemoveItem = Meteor._localStorage.removeItem;
Meteor._localStorage.removeItem = function removeItem(key) {
  if (key === 'Meteor.loginToken') {
    Meteor.defer(resetToken);
  }
  originalRemoveItem.call(Meteor._localStorage, key);
};

import Cookies from 'universal-cookie';

import { Meteor } from 'meteor/meteor';

import { getRenderContext } from './render_context.js';

const cookie = new Cookies();

function setToken(loginToken, expires) {
  if (loginToken && expires !== -1) {
    cookie.set('meteor_login_token', loginToken, {
      path: '/',
      expires,
    });
  } else {
    cookie.remove('meteor_login_token', {
      path: '/',
    });
  }
}

function resetToken() {
  const context = getRenderContext();
  const loginToken = global.localStorage['Meteor.loginToken'];
  const loginTokenExpires = new Date(global.localStorage['Meteor.loginTokenExpires']);

  if (loginToken) {
    setToken(loginToken, loginTokenExpires);
  } else {
    setToken(null, -1);
  }

  context.loginToken = loginToken;
}

Meteor.startup(() => {
  resetToken();
});

const originalSetItem = Meteor._localStorage.setItem;
Meteor._localStorage.setItem = function setItem(key, value) {
  if (key === 'Meteor.loginToken') {
    Meteor.defer(resetToken);
  }
  originalSetItem.call(Meteor._localStorage, key, value);
};

const originalRemoveItem = Meteor._localStorage.removeItem;
Meteor._localStorage.removeItem = function removeItem(key) {
  if (key === 'Meteor.loginToken') {
    Meteor.defer(resetToken);
  }
  originalRemoveItem.call(Meteor._localStorage, key);
};

Update cookies to use universal-cookie


import React, { Component } from 'react';
import { Text, Image, View } from 'react-native';
import styles from './styles/ActorsMoviesStyle';
import ActorImage from '../components/ActorImage';
import { StackNagivator } from 'react-navigation';

export default class ActorsMovies extends Component {
  render() {
    return (
      <Text>Movies!</Text>
    )
  }
}

import React, { Component } from 'react';
import { Text, Image, View } from 'react-native';
import styles from './styles/ActorsMoviesStyle';
import ActorImage from '../components/ActorImage';
import { StackNagivator } from 'react-navigation';

export default class ActorsMovies extends Component {
  render() {
    return (
      <Text>Movies</Text>
    )
  }
}

Add another test commit for changing login


'use strict';
var crypto = require('crypto')
var Transform = require('stream').PassThrough
var util = require('util')

/**
 * Constructor
 * @constructor
 * @param {object} options
 */
var SHA1Stream = function(options){
  var that = this
  Transform.call(that,options)
  that.shasum = crypto.createHash('sha1')
  that.sha1 = null
  that.on('finish',function(){
    that.sha1 = that.shasum.digest('hex')
    that.emit('sha1',that.sha1)
  })
}
util.inherits(SHA1Stream,Transform)

/**
 * Transform data
 * @param {Buffer} chunk
 * @param {string} encoding
 * @param {function} done
 */
SHA1Stream.prototype._transform = function(chunk,encoding,done){
  try {
    this.shasum.update(chunk)
    this.push(chunk)
    done()
  } catch(e){
    done(e)
  }
}

/**
 * Export helper
 * @type {SHA1Stream}
 */
module.exports = SHA1Stream

'use strict';
var crypto = require('crypto')
var Transform = require('stream').PassThrough
var util = require('util')

/**
 * Constructor
 * @constructor
 * @param {string} hash type defaults to sha1
 * @param {object} options
 */
var SHAStream = function(hashType,options){
  var that = this
  that.hashType = hashType || 'sha1'
  Transform.call(that,options)
  that.sum = crypto.createHash(that.hashType)
  that[that.hashType] = null
  that.on('finish',function(){
    that[that.hashType] = that.sum.digest('hex')
    that.emit(hashType,that[that.hashType])
    that.emit(that.hashType,that[that.hashType])
  })
}
util.inherits(SHAStream,Transform)

/**
 * Transform data
 * @param {Buffer} chunk
 * @param {string} encoding
 * @param {function} done
 */
SHAStream.prototype._transform = function(chunk,encoding,done){
  try {
    this.sum.update(chunk)
    this.push(chunk)
    done()
  } catch(e){
    done(e)
  }
}

/**
 * Export helper
 * @type {SHAStream}
 */
module.exports = SHAStream

Change for 0.2 to use generic hash streams


function dominantDirection(text) {
    let scripts = countBy(text, char => {
        let script = characterScript(char.codePointAt(0));
        return script ? script.direction : "none";
    }).filter(({name}) => name != "none");

    if (counted.length == 0) return "ltr";

    return scripts.reduce((a, b) => a.count > b.count ? a : b).name;
}

function dominantDirection(text) {
	return countBy(text, char => {
		let script = characterScript(char.codePointAt(0));
		return script ? script.direction : "none";
	}).filter(({name}) => name != "none").
		reduce((a, b) => a.count > b.count ? a : b).name;
}

Add chapter 5, exercise 4


/* jshint node: true */

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

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

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

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

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

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

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

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

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

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

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

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

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

  if (environment === 'production') {
    ENV.baseURL = '/emberx-select'
  }

  return ENV;
};

Update config file for gh-pages assests path


/*jshint node:true*/
/* global require, module */

var EmberApp = require( 'ember-cli/lib/broccoli/ember-app' );

module.exports = function( defaults ) {

	var app = new EmberApp( defaults, {

		outputPaths: {

			app: {
				js: '/assets/app.js',
				css: {
					'app': '/assets/styles.css'
				}
			}

		},

		minifyJS: {
			enabled: false
		}

	});

	// Use `app.import` to add additional libraries to the generated output files.
	return app.toTree();

}

/*jshint node:true*/
/* global require, module */

var EmberApp = require( 'ember-cli/lib/broccoli/ember-app' );

module.exports = function( defaults ) {

	var app = new EmberApp( defaults, {

		outputPaths: {

			app: {
				js: '/assets/app.js',
				css: {
					'app': '/assets/styles.css'
				}
			}

		}

	});

	// Use `app.import` to add additional libraries to the generated output files.
	return app.toTree();

}

Allow minification of JS in production


const maxWidth = process.argv[2] || 80

const stdin = process.stdin,
      stdout = process.stdout,
      inputChunks = []

stdin.resume()
stdin.setEncoding('utf8')

stdin.on('data', function (chunk) {
    inputChunks.push(chunk)
});

stdin.on('end', function () {
    var inputJSON = inputChunks.join(),
        parsedData = JSON.parse(inputJSON),
        outputJSON = prettyPrint(parsedData,'')
    stdout.write(outputJSON)
    stdout.write('\n')
});

function prettyPrint(obj,indent) {
  const text = JSON.stringify(obj)
  if((text + indent).length < maxWidth || typeof obj === 'string') {
    return text
  } else if(Object.keys(obj).length === 1) {
    // To stack object with a  single prop into one line:
    for(const prop in obj) {
      return '{"' + prop + '":' + prettyPrint(obj[prop],indent) + '}'
    }
  } else {
    const arr = []
    for(const prop in obj) {
      arr.push(indent + '  "' + prop + '":' + prettyPrint(obj[prop],indent+'  '))
    }
    return '{\n' + arr.join(',\n') + '\n' + indent + '}'
    // for smooshed format: return '{\n' + arr.join(',\n') + '}'
  }
}

const maxWidth = process.argv[2] || 80

const stdin = process.stdin,
      stdout = process.stdout,
      inputChunks = []

stdin.resume()
stdin.setEncoding('utf8')

stdin.on('data', function (chunk) {
    inputChunks.push(chunk)
});

stdin.on('end', function () {
    var inputJSON = inputChunks.join(),
        parsedData = JSON.parse(inputJSON),
        outputJSON = prettyPrint(parsedData,'')
    stdout.write(outputJSON)
    stdout.write('\n')
});

function prettyPrint(obj,indent) {
  const text = JSON.stringify(obj)
  if((text + indent).length < maxWidth || typeof obj === 'string') {
    return text
  } else if(Array.isArray(obj)) {
    const arr = []
    for(const item of obj) {
      arr.push(indent + prettyPrint(item,indent+'  '))
    }
    return '[\n' + arr.join(',\n') + '\n' + indent + ']'
  } else if(Object.keys(obj).length === 1) {
    // To stack object with a  single prop into one line:
    for(const prop in obj) {
      return '{"' + prop + '":' + prettyPrint(obj[prop],indent) + '}'
    }
  } else {
    const arr = []
    for(const prop in obj) {
      arr.push(indent + '  "' + prop + '":' + prettyPrint(obj[prop],indent+'  '))
    }
    return '{\n' + arr.join(',\n') + '\n' + indent + '}'
    // for smooshed format: return '{\n' + arr.join(',\n') + '}'
  }
}

Fix bug where long arrays were treated as objects


import { MongoClient } from 'mongodb';

const MONGODB_URI = process.env.MONGODB_URI;

// Database Name
const dbName = 'cofacts';

export default class CofactsMongoClient {
  /**
   * @type {?Promise<CofactsMongoClient>}
   */
  static _instance = null;

  static async getInstance() {
    if (this._instance === null) {
      this._instance = new Promise(async (resolve, reject) => {
        const client = new CofactsMongoClient(MONGODB_URI);
        try {
          await client.mongoClient.connect();
          resolve(client);
        } catch (e) {
          reject(e);
        }
      });
    }
    return this._instance;
  }

  constructor(uri, options) {
    this.mongoClient = new MongoClient(uri, options);
  }

  get db() {
    return this.mongoClient.db(dbName);
  }

  /**
   *
   * @param {string} name
   */
  async collection(name) {
    return this.db.collection(name);
  }

  async close() {
    return this.mongoClient.close();
  }
}

import { MongoClient } from 'mongodb';

const MONGODB_URI = process.env.MONGODB_URI;

// Database Name
const dbName = 'cofacts';

export default class CofactsMongoClient {
  /**
   * @type {?Promise<CofactsMongoClient>}
   */
  static _instance = null;

  static async getInstance() {
    if (this._instance === null) {
      this._instance = new Promise(async (resolve, reject) => {
        const client = new CofactsMongoClient(MONGODB_URI);
        try {
          await client.mongoClient.connect();
          resolve(client);
        } catch (e) {
          reject(e);
        }
      });
    }
    return this._instance;
  }

  constructor(uri, options) {
    this.mongoClient = new MongoClient(uri, options);
  }

  get db() {
    return this.mongoClient.db(dbName);
  }

  /**
   *
   * @param {string} name
   */
  async collection(name) {
    return this.db.collection(name);
  }

  async close() {
    await this.mongoClient.close();
    this._instance = null;
  }
}

Set instance to null if client is closed


App.RawTransform = DS.Transform.extend({
  deserialize: function(serialized) {
    return serialized;
  },
  serialize: function(deserialized) {
    return deserialized;
  }
});

App.ArrayTransform = App.RawTransform.extend({});
App.TimestampTransform = DS.NumberTransform.extend({});
App.ChoiceTransform = DS.StringTransform.extend();

App.TumblrStringTransform = DS.StringTransform.extend({
  deserialize: function(serialized){
    'use strict';
    var deserialized = this._super(serialized),
        self = this,
        router = this.container.lookup('router:main'), url;

    // return if null
    if (Ember.isNone(deserialized))
      return null;

    // reformat tumblr urls appropriately
    return deserialized.replace(/href="http:\/\/([^\.]*).tumblr.com\/([^"]*)"/g, function(orig, blog_name, path, idx, full){
      if (!Em.isEmpty(path)){
        path = /post\/(\d+)\/(.*)?/.exec(path);
        var post_ident = path[1],
            post_slug = path[2];

        url = router.router.recognizer.generate('single_post', {
          blog_name: blog_name,
          post_id: post_ident,
          post_slug: post_slug
        });

      } else {
        url = router.router.recognizer.generate('single_blog', {blog_name: blog_name});
      }

      url = router.get('location').formatURL(url);
      if (url.charAt(0) !== '/') { url = '/' + url; }

      return 'href="%@"'.fmt(url);
    });
  }
});

App.RawTransform = DS.Transform.extend({
  deserialize: function(serialized) {
    return serialized;
  },
  serialize: function(deserialized) {
    return deserialized;
  }
});

App.ArrayTransform = App.RawTransform.extend({});
App.TimestampTransform = DS.NumberTransform.extend({});
App.ChoiceTransform = DS.StringTransform.extend();

App.TumblrStringTransform = DS.StringTransform.extend({
  deserialize: function(serialized){
    'use strict';
    var deserialized = this._super(serialized),
        self = this,
        router = this.container.lookup('router:main'), url;

    // return if null
    if (Ember.isNone(deserialized))
      return null;

    // reformat tumblr urls appropriately
    return deserialized.replace(/href="http:\/\/([^\.]*).tumblr.com\/([^"]*)"/g, function(orig, blog_name, path, idx, full){
      if (!Em.isEmpty(path)){
        path = /post\/(\d+)\/?(.*)?/.exec(path);
        var post_ident = path[1],
            post_slug = path[2];

        url = router.router.recognizer.generate('single_post', {
          blog_name: blog_name,
          post_ident: post_ident,
          post_slug: post_slug
        });

      } else {
        url = router.router.recognizer.generate('single_blog', {blog_name: blog_name});
      }

      url = router.get('location').formatURL(url);
      if (url.charAt(0) !== '/') { url = '/' + url; }

      return 'href="%@"'.fmt(url);
    });
  }
});

Allow post urls without slugs to be transformed


'use strict';

const template = require('../views/index.hbs');
const Logo = require('./components/Logo.js');
const CurrentWeather = require('./pages/CurrentWeather.js');
const ForecastWeather = require('./pages/ForecastWeather.js');
const Search = require('./components/Search.js');
const ErrorPage = require('./pages/ErrorPage.js');

class App {

	constructor() {
		this._render();
	}

	_render() {
		let container = document.querySelector('.app-container');
		container.innerHTML = template();

		let logo = new Logo();
		container.querySelector('.show-box').appendChild(logo.container);

		let currentWeather = new CurrentWeather();
		container.querySelector('.show-box').appendChild(currentWeather.container);

		let forecastWeather = new ForecastWeather();
		container.querySelector('.show-box').appendChild(forecastWeather.container);

		let search = new Search(logo, currentWeather, forecastWeather);
		container.querySelector('.app').appendChild(search.container);

		let errorPage = new ErrorPage();
		container.querySelector('.show-box').appendChild(errorPage.container);

	}
}

module.exports = App;

'use strict';

const template = require('../views/index.hbs');
const Logo = require('./components/Logo.js');
const CurrentWeather = require('./pages/CurrentWeather.js');
const ForecastWeather = require('./pages/ForecastWeather.js');
const Search = require('./components/Search.js');
const ErrorPage = require('./pages/ErrorPage.js');

class App {

	constructor() {
		this._render();
	}

	_render() {
		let container = document.querySelector('.app-container');
		container.innerHTML = template();

		let logo = new Logo();
		container.querySelector('.top').appendChild(logo.container);

		let currentWeather = new CurrentWeather();
		container.querySelector('.show-box').appendChild(currentWeather.container);

		let forecastWeather = new ForecastWeather();
		container.querySelector('.show-box').appendChild(forecastWeather.container);

		let search = new Search(logo, currentWeather, forecastWeather);
		container.querySelector('.app').appendChild(search.container);

		let errorPage = new ErrorPage();
		container.querySelector('.show-box').appendChild(errorPage.container);

	}
}

module.exports = App;

Replace logo to top box


#!/usr/bin/env node

/*
* SQL API loader
* ===============
*
* node app [environment]
*
* environments: [development, test, production]
*
*/
var _ = require('underscore');

// sanity check arguments
var ENV = process.argv[2];
if (ENV != 'development' && ENV != 'production' && ENV != 'test') {
  console.error("\n./app [environment]");
  console.error("environments: [development, test, production]");
  process.exit(1);
}

// set Node.js app settings and boot
global.settings  = require(__dirname + '/config/settings');
var env          = require(__dirname + '/config/environments/' + ENV);
_.extend(global.settings, env);

// kick off controller
if ( ! global.settings.base_url ) global.settings.base_url = '/api/*';
var app = require(global.settings.app_root + '/app/controllers/app');
app.listen(global.settings.node_port, global.settings.node_host, function() {
  console.log("CartoDB SQL API listening on " +
      global.settings.node_host + ":" + global.settings.node_port +
      " with base_url " + global.settings.base_url);
});

#!/usr/bin/env node

/*
* SQL API loader
* ===============
*
* node app [environment]
*
* environments: [development, test, production]
*
*/
var _ = require('underscore');

// sanity check arguments
var ENV = process.argv[2];
if (ENV != 'development' && ENV != 'production' && ENV != 'test' && ENV != 'staging' ) {
  console.error("\n./app [environment]");
  console.error("environments: [development, staging, production, test]");
  process.exit(1);
}

// set Node.js app settings and boot
global.settings  = require(__dirname + '/config/settings');
var env          = require(__dirname + '/config/environments/' + ENV);
_.extend(global.settings, env);

// kick off controller
if ( ! global.settings.base_url ) global.settings.base_url = '/api/*';
var app = require(global.settings.app_root + '/app/controllers/app');
app.listen(global.settings.node_port, global.settings.node_host, function() {
  console.log("CartoDB SQL API listening on " +
      global.settings.node_host + ":" + global.settings.node_port +
      " with base_url " + global.settings.base_url);
});

Allow 'staging' as an env name for non-clustered run


var eventStream = require('event-stream'),
    gulp = require('gulp'),
    chmod = require('gulp-chmod'),
    zip = require('gulp-zip'),
    tar = require('gulp-tar'),
    gzip = require('gulp-gzip'),
    rename = require('gulp-rename');

gulp.task('prepare-release', function() {
    var version = require('./package.json').version;

    return eventStream.merge(
        getSources()
            .pipe(zip('operator-status-plugin-' + version + '.zip')),
        getSources()
            .pipe(tar('operator-status-plugin-' + version + '.tar'))
            .pipe(gzip())
    )
    .pipe(chmod(0644))
    .pipe(gulp.dest('release'));
});

// Builds and packs plugins sources
gulp.task('default', ['prepare-release'], function() {
    // The "default" task is just an alias for "prepare-release" task.
});

/**
 * Returns files stream with the plugin sources.
 *
 * @returns {Object} Stream with VinylFS files.
 */
var getSources = function() {
    return gulp.src([
            'Controller/*',
            'LICENSE',
            'Plugin.php',
            'README.md',
            'routing.yml'
        ],
        {base: './'}
    )
    .pipe(rename(function(path) {
        path.dirname = 'Mibew/Mibew/Plugin/OperatorStatus/' + path.dirname;
    }));
}

var eventStream = require('event-stream'),
    gulp = require('gulp'),
    chmod = require('gulp-chmod'),
    zip = require('gulp-zip'),
    tar = require('gulp-tar'),
    gzip = require('gulp-gzip'),
    rename = require('gulp-rename');

gulp.task('prepare-release', function() {
    var version = require('./package.json').version;

    return eventStream.merge(
        getSources()
            .pipe(zip('operator-status-plugin-' + version + '.zip')),
        getSources()
            .pipe(tar('operator-status-plugin-' + version + '.tar'))
            .pipe(gzip())
    )
    .pipe(chmod(644))
    .pipe(gulp.dest('release'));
});

// Builds and packs plugins sources
gulp.task('default', ['prepare-release'], function() {
    // The "default" task is just an alias for "prepare-release" task.
});

/**
 * Returns files stream with the plugin sources.
 *
 * @returns {Object} Stream with VinylFS files.
 */
var getSources = function() {
    return gulp.src([
            'Controller/*',
            'LICENSE',
            'Plugin.php',
            'README.md',
            'routing.yml'
        ],
        {base: './'}
    )
    .pipe(rename(function(path) {
        path.dirname = 'Mibew/Mibew/Plugin/OperatorStatus/' + path.dirname;
    }));
}

Fix invalid bitmask for release archives


'use strict';

var fs = require('fs');
var program = require('../../parser/program.js');
var Parsimmon = require('parsimmon');

module.exports = readJSigAST;

function readJSigAST(fileName) {
    if (!fs.existsSync(fileName)) {
        return new Result(null, null);
    }

    var source = fs.readFileSync(fileName, 'utf8');
    return parseJSigAST(source);
}

function parseJSigAST(source) {
    var res = program.parse(source);

    if (res.status) {
        return new Result(null, res.value);
    }

    var message = Parsimmon.formatError(source, res);
    var error = new Error(message);
    return new Result(error, null);
}

function Result(err, value) {
    this.error = err;
    this.value = value;
}

'use strict';

var fs = require('fs');
var program = require('../../parser/program.js');
var Parsimmon = require('parsimmon');

module.exports = readJSigAST;

function readJSigAST(fileName) {
    if (!fs.existsSync(fileName)) {
        return new Result(null, null);
    }

    var source = fs.readFileSync(fileName, 'utf8');
    return parseJSigAST(source);
}

function parseJSigAST(source) {
    var res = program.parse(source);

    if (res.status) {
        return new Result(null, res.value);
    }

    var message = formatError(source, res);
    var error = new Error(message);
    return new Result(error, null);
}

function Result(err, value) {
    this.error = err;
    this.value = value;
}

function formatError(source, error) {
    return 'expected ' + formatExpected(error.expected) +
        formatGot(source, error);
}

function formatExpected(expected) {
    if (expected.length === 1) {
        return expected[0];
    }

    return 'one of ' + expected.join(', ');
}

function formatGot(stream, error) {
    var index = error.index;

    if (index === stream.length) {
        return ', got the end of the stream';
    }

    var prefix = (index > 0 ? '"...' : '"');
    var suffix = (stream.length - index > 12 ? '..."' : '"');

    var lines = stream.split('\n');
    var soFar = 0;
    var lineNo = 0;
    var columnNo = 0;
    for (var i = 0; i < lines.length; i++) {
        if (index < soFar + lines[i].length) {
            columnNo = index - soFar + 1;
            lineNo = i + 1;
            break;
        }

        soFar += lines[i].length + 1;
    }

    return ' at line ' + lineNo + ':' + columnNo + ' , got ' +
        prefix + stream.slice(index, index + 12) + suffix;
}

Add better error message formatting


'use strict';

exports.filterPlatforms = filterPlatforms;
function filterPlatforms(platform) {
  var browser = platform.browserName;
  var version = platform.version;
  if (version === 'dev' || version === 'beta') return false;
  version = +version;
  if (browser === 'chrome') {
    return version >= 53 || version % 5 === 0;
  }
  if (browser === 'firefox') {
    return version >= 47 || version % 5 === 0 || version === 3.6;
  }
  return true;
}

exports.choosePlatforms = choosePlatforms;
function choosePlatforms(platforms) {
  return [platforms[Math.floor(Math.random() * platforms.length)]];
}

'use strict';

exports.filterPlatforms = filterPlatforms;
function filterPlatforms(platform) {
  var browser = platform.browserName;
  var version = platform.version;
  if (version === 'dev' || version === 'beta') return false;
  version = +version;
  if (browser === 'chrome') {
    return version >= 53 || version % 5 === 0;
  }
  if (browser === 'firefox') {
    return version >= 47 || version % 5 === 0 || version === 3.6;
  }
  // sauce labs have issues testing v4.3 and under
  if (browser === 'android') {
    return version >= 4.3;
  }
  return true;
}

exports.choosePlatforms = choosePlatforms;
function choosePlatforms(platforms) {
  return [platforms[Math.floor(Math.random() * platforms.length)]];
}

Disable old android by default


document.addEventListener('click', function(event) {
  var form, input, method, element;

  element = event.target;

  if (matches.call(element, 'a[data-method]')) {
    if (matches.call(element, 'a[data-remote]')) {
      return true;
    }

    method = element.getAttribute('data-method').toLowerCase();
    if (method == 'get') {
      return true;
    }

    form = document.createElement('form');
    form.method = 'POST';
    form.action = element.getAttribute('href');
    form.style.display = 'none';

    if (method != 'post') {
      input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', '_method');
      input.setAttribute('value', method);
      form.appendChild(input);
    }

    document.body.appendChild(form);
    form.submit();
    event.preventDefault();
  }
}, false);

document.addEventListener('click', function(event) {
  var form, input, method, element;

  element = event.target;

  if (matches.call(element, 'a[data-method]')) {
    if (matches.call(element, 'a[data-remote]')) {
      return true;
    }

    method = element.getAttribute('data-method').toUpperCase();
    if (method == 'GET') {
      return true;
    }

    form = document.createElement('form');
    form.method = 'POST';
    form.action = element.getAttribute('href');
    form.style.display = 'none';

    if (method != 'POST') {
      input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', '_method');
      input.setAttribute('value', method);
      form.appendChild(input);
    }

    document.body.appendChild(form);
    form.submit();
    event.preventDefault();
  }
}, false);

Use upper case when testing for HTTP request type


var gulp = require('gulp');
var less = require('gulp-less');
var cleancss = require('gulp-clean-css');
var csscomb = require('gulp-csscomb');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var LessPluginAutoPrefix = require('less-plugin-autoprefix');

var autoprefix= new LessPluginAutoPrefix({ browsers: ["last 4 versions"] });

gulp.task('watch', function() {
    gulp.watch('./**/*.less', ['build']);
});

gulp.task('build', function() {
    gulp.src('./src/less/*.less')
        .pipe(less({
            plugins: [autoprefix]
        }))
        .pipe(csscomb())
        .pipe(gulp.dest('./src/css'));
});

gulp.task('minify', function() {
    gulp.src('./src/css/*.css')
        .pipe(concat('affinity.css'))
        .pipe(cleancss())
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(gulp.dest('./assets'));
    gulp.src('./src/js/*.js')
        .pipe(concat('affinity.js'))
        .pipe(uglify())
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(gulp.dest('./assets'));
});

gulp.task('default', ['build']);

var gulp = require('gulp');
var less = require('gulp-less');
var cleancss = require('gulp-clean-css');
var csscomb = require('gulp-csscomb');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var LessPluginAutoPrefix = require('less-plugin-autoprefix');

var autoprefix= new LessPluginAutoPrefix({ browsers: ["last 4 versions"] });

gulp.task('watch', function() {
    gulp.watch('./**/*.less', ['build', 'minify']);
});

gulp.task('build', function() {
    gulp.src('./src/less/*.less')
        .pipe(less({
            plugins: [autoprefix]
        }))
        .pipe(csscomb())
        .pipe(gulp.dest('./src/css'));
});

gulp.task('minify', function() {
    gulp.src('./src/css/*.css')
        .pipe(concat('affinity.css'))
        .pipe(cleancss())
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(gulp.dest('./assets'));
    gulp.src('./src/js/*.js')
        .pipe(concat('affinity.js'))
        .pipe(uglify())
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(gulp.dest('./assets'));
});

gulp.task('default', ['build']);

Add `minify` to gulp watch


var gulp = require('gulp');
var bs = require('browser-sync').create();

gulp.task('default', function() {
  bs.init({
    server: {
      baseDir: "./app",
      routes: {
        "/lib": "bower_components"
      }
    }
  });
});

var gulp = require('gulp');
var bs = require('browser-sync').create();
var reload = bs.reload;

gulp.task('default', function() {
  bs.init({
    server: {
      baseDir: "./app",
      routes: {
        "/lib": "bower_components"
      }
    }
  });

  gulp.watch("app/**/*.html").on('change', reload);
  gulp.watch("app/scripts/**/*.js").on('change', reload);
});

Update gulp to watch scripts and html


function NotFoundError(message) {
  this.name = 'Not found';
  this.message = message || '';
  this.status = 404;
}

NotFoundError.prototype = Error.prototype;

module.exports = NotFoundError;

function NotFoundError(message) {
  this.name = 'Not found';
  this.message = message || 'Not found';
  this.status = 404;
}

NotFoundError.prototype = Error.prototype;

module.exports = NotFoundError;

Add a 'not found' message to not found error


var Montage = require("montage").Montage;

/**
 * Defines the criteria that objects must satisfy to be included in a data set
 * as well as other characteristics the data set must possess.
 *
 * @class
 * @extends external:Montage
 */
exports.DataSelector = Montage.specialize(/** @lends DataSelector# */{

    /**
     * The type of the data object to retrieve.
     *
     * @type {ObjectDescriptor}
     */
    type: {
        value: undefined
    },

    /**
     * A set of named values defining the criteria that must be satisfied by
     * objects for them to be included in the data set defined by this selector.
     *
     * Properties and corresponding values can be added or removed from the
     * criteria object but that criteria object itself cannot be replaced.
     *
     * @type {Object}
     */
    criteria: {
        get: function () {
            if (!this._criteria) {
                this._criteria = {};
            }
            return this._criteria;
        }
    }

});

var Montage = require("montage").Montage;

/**
 * Defines the criteria that objects must satisfy to be included in a data set
 * as well as other characteristics the data set must possess.
 *
 * @class
 * @extends external:Montage
 */
exports.DataSelector = Montage.specialize(/** @lends DataSelector# */{

    /**
     * The type of the data object to retrieve.
     *
     * @type {ObjectDescriptor}
     */
    type: {
        value: undefined
    },

    /**
     * A set of named values defining the criteria that must be satisfied by
     * objects for them to be included in the data set defined by this selector.
     *
     * Properties and corresponding values can be added or removed from the
     * criteria object but that criteria object itself cannot be replaced.
     *
     * @type {Object}
     */
    criteria: {
        get: function () {
            if (!this._criteria) {
                this._criteria = {};
            }
            return this._criteria;
        }
    }

}, {

    for: {
        value: function (type, criteria) {
            var selector, key;
            selector = new DataSelector;
            selector.type = type;
            if (criteria) {
                for (key in criteria) {
                    selector.criteria[key] = criteria[key];
                }
            }
            return selector;
        }
    }

});

Add a DataSelector creation convenience method


import uuid from 'node-uuid'

const id = uuid.v4()

if (typeof window === 'undefined') {
  var peer = { id: id }
} else {
  let Peer = require('peerjs')
  var peer = new Peer(id, {
    host: window.location.hostname,
    port: window.location.port,
    path: '/peer',
    config: {
      iceServers: [{
        'url': 'stun:stun.l.google.com:19302'
      }, {
        'url': 'turn:52.12.205.113:3478?transport=udp',
        'username': 'file',
        'credential': 'pizza'
      }, {
        'url': 'turn:52.12.205.113:3479?transport=udp',
        'username': 'file',
        'credential': 'pizza'
      }, {
        'url': 'turn:52.12.205.113:3478?transport=tcp',
        'username': 'file',
        'credential': 'pizza'
      }, {
        'url': 'turn:52.12.205.113:3479?transport=tcp',
        'username': 'file',
        'credential': 'pizza'
      }]
    }
  })
}

export default peer

import uuid from 'node-uuid'

const id = uuid.v4()

if (typeof window === 'undefined') {
  var peer = { id: id }
} else {
  let Peer = require('peerjs')
  var peer = new Peer(id, {
    host: window.location.hostname,
    port: window.location.port,
    path: '/peer',
    config: {
      iceServers: [{
        'url': 'stun:stun.l.google.com:19302'
      }, {
        'url': 'turn:52.12.205.113:3478?transport=udp',
        'username': 'file',
        'credential': 'pizza'
      }, {
        'url': 'turn:52.12.205.113:80?transport=udp',
        'username': 'file',
        'credential': 'pizza'
      }, {
        'url': 'turn:52.12.205.113:3478?transport=tcp',
        'username': 'file',
        'credential': 'pizza'
      }, {
        'url': 'turn:52.12.205.113:80?transport=tcp',
        'username': 'file',
        'credential': 'pizza'
      }]
    }
  })
}

export default peer

Use port 80 to get around firewalls


const Core = require('./core/index.js')

// Parent
const Plugin = require('./plugins/Plugin')

// Orchestrators
const Dashboard = require('./plugins/Dashboard/index.js')

// Acquirers
const Dummy = require('./plugins/Dummy')
const DragDrop = require('./plugins/DragDrop/index.js')
const FileInput = require('./plugins/FileInput.js')
const GoogleDrive = require('./plugins/GoogleDrive/index.js')
const Dropbox = require('./plugins/Dropbox/index.js')
const Instagram = require('./plugins/Instagram/index.js')
const Webcam = require('./plugins/Webcam/index.js')

// Progressindicators
const ProgressBar = require('./plugins/ProgressBar.js')
const Informer = require('./plugins/Informer.js')

// Modifiers
const MetaData = require('./plugins/MetaData.js')

// Uploaders
const Tus10 = require('./plugins/Tus10')
const XHRUpload = require('./plugins/XHRUpload')
const Transloadit = require('./plugins/Transloadit')

module.exports = {
  Core,
  Plugin,
  Dummy,
  ProgressBar,
  Informer,
  DragDrop,
  GoogleDrive,
  Dropbox,
  Instagram,
  FileInput,
  Tus10,
  XHRUpload,
  Transloadit,
  Dashboard,
  MetaData,
  Webcam
}

const Core = require('./core/index.js')

// Parent
const Plugin = require('./plugins/Plugin')

// Orchestrators
const Dashboard = require('./plugins/Dashboard/index.js')

// Acquirers
const Dummy = require('./plugins/Dummy')
const DragDrop = require('./plugins/DragDrop/index.js')
const FileInput = require('./plugins/FileInput.js')
const GoogleDrive = require('./plugins/GoogleDrive/index.js')
const Dropbox = require('./plugins/Dropbox/index.js')
const Instagram = require('./plugins/Instagram/index.js')
const Webcam = require('./plugins/Webcam/index.js')

// Progressindicators
const ProgressBar = require('./plugins/ProgressBar.js')
const Informer = require('./plugins/Informer.js')

// Modifiers
const MetaData = require('./plugins/MetaData.js')

// Uploaders
const Tus10 = require('./plugins/Tus10')
const XHRUpload = require('./plugins/XHRUpload')
const Transloadit = require('./plugins/Transloadit')
const AwsS3 = require('./plugins/AwsS3')

module.exports = {
  Core,
  Plugin,
  Dummy,
  ProgressBar,
  Informer,
  DragDrop,
  GoogleDrive,
  Dropbox,
  Instagram,
  FileInput,
  Tus10,
  XHRUpload,
  Transloadit,
  AwsS3,
  Dashboard,
  MetaData,
  Webcam
}

Add AwsS3 to the dist bundle.


angular.module('Gistter')

.config(['$routeProvider', function($routeProvider) {
  $routeProvider

    .when('/', {
      controller: 'TwitterController',
      templateUrl: 'templates/index/index.html'
    });

}]);

angular.module('Gistter')

.config(['$routeProvider', function($routeProvider) {
  $routeProvider

    .when('/tweets', {
      controller: 'TwitterController',
      templateUrl: 'templates/index/tweets.html'
    })
    .when('/repos', {
      controller: 'TwitterController',
      templateUrl: 'templates/index/repos.html'
    })
    .otherwise('/tweets', {
      controller: 'TwitterController',
      templateUrl: 'templates/index/tweets.html'
    });

}]);

Add otherwise route, change routes to tweets & repos


(function($){
  var textNode = function(node, search, replace, capturing) {
    var tokens = node.nodeValue.split(search);
    if (tokens.length < 2) return false;
    for (var i = 0; i+capturing < tokens.length; i += capturing+1) {
      $(node).before(document.createTextNode(tokens[i]));
      $(node).before(replace(tokens.slice(i+1, i+1+capturing)));
    }
    $(node).before(document.createTextNode(tokens[tokens.length-1]));
    return true;
  };

  /**
   * Replace substrings with HTML.
   *
   * @param node A text node.
   * @param search A RegExp object that must have at least one capturing subgroup.
   * @param replace A function that generates the replacement jQuery content.
   * @param groups (optional) The number of capturing subgroups in the RegExp.
   */
  $.fn.replaceText = function(search, replace, capturing) {
    capturing = capturing || 1;
    return this.each(function() {
      var remove = [];
      for (var node = this.firstChild; node; node = node.nextSibling) {
        if (node.nodeType == document.TEXT_NODE && textNode(node, search, replace, capturing)) {
          remove.push(node);
        }
      }
      $(remove).remove();
    });
  }
})(jQuery);

(function($){
  var textNode = function(node, search, replace, capturing) {
    var tokens = node.nodeValue.split(search);
    if (tokens.length < 2) return false;
    for (var i = 0; i+capturing < tokens.length; i += capturing+1) {
      $(node).before(document.createTextNode(tokens[i]));
      $(node).before(replace(tokens.slice(i+1, i+1+capturing)));
    }
    $(node).before(document.createTextNode(tokens[tokens.length-1]));
    return true;
  };

  /**
   * Replace substrings with HTML.
   *
   * @param node A text node.
   * @param search A RegExp object that must have at least one capturing subgroup.
   * @param replace A function that generates the replacement jQuery content.
   */
  $.fn.replaceText = function(search, replace) {
    var capturing = RegExp(search.source + '|').exec('').length - 1;
    return this.each(function() {
      var remove = [];
      for (var node = this.firstChild; node; node = node.nextSibling) {
        if (node.nodeType == document.TEXT_NODE && textNode(node, search, replace, capturing)) {
          remove.push(node);
        }
      }
      $(remove).remove();
    });
  }
})(jQuery);

Make replaceText() count the sub-groups.


// Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.

function errorAlert(data) {
    var title, msg;
    if (data.status == 0) {
        title = 'An error occurred!';
        msg = '
The server may be down.
';
    } else {
        title = data.status + ': ' + data.statusText;
        msg = data.responseText;
    }
    bootbox.dialog({
        title: title,
        message: msg,
    });
}

// Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.

function errorAlert(data) {
    var title, msg;
    if (data.status == 0) {
        title = 'An error occurred!';
        msg = '
The server may be down.
';
    } else {
        title = data.status + ': ' + data.statusText;
        msg = data.responseText;
    }
    bootbox.alert({
        title: title,
        message: msg,
    });
}

Enable closing error messages with ESC


import express from 'express';
import bodyParser from 'body-parser';

import { startDB } from '../db/config';
import api from './api';

async function application (config) {
  const app = express();

  app.set('config', config);
  app.use(bodyParser.json());

  await startDB();

  api(app);

  return app;
}

export const start = (config) => new Promise(async resolve => {
  const app = await application(config);
  app.listen(config.http.port, config.http.host, () => {
    /* eslint-disable no-console */
    console.info(`Server started at [ http://${config.http.host}:${config.http.port} ]`);

    resolve();
  });
});

import express from 'express';
import bodyParser from 'body-parser';

import { startDB } from '../db/config';
import api from './api';

async function application (config) {
  const app = express();

  app.set('config', config);
  app.use(bodyParser.json());

  await startDB();

  api(app);

  return app;
}

export const start = (config) => new Promise(async resolve => {
  const app = await application(config);
  app.listen(config.http.port, config.http.host, () => {
    /* eslint-disable no-console */
    console.info(`message-service started at [ http://${config.http.host}:${config.http.port} ]`);

    resolve();
  });
});

Add service name on start log


const gulp = require('gulp'),
    rename = require('gulp-rename'),
    less = require('gulp-less'),
    pug = require('gulp-pug')
    argv = require('yargs').argv

/**
 * Compile less to css and minify
 */
gulp.task('less', function () {

    gulp.src('./src/less/**/*.less')
        .pipe(less({
            compress:true
        }))
        .pipe(gulp.dest('./src/css/'));

});

// Build template
gulp.task('export', function () {
    if (!argv.template)
        return console.log("Please enter template name --template <templatename>");

    const templateName = argv.template;

    return gulp.src('./templates/' + templateName + '/index.pug')
        .pipe(pug(

        ))
        .pipe(rename( templateName + '.xml'))
        .pipe(gulp.dest('./build'))
})

// Auto compile
gulp.task('autocompile', function () {
    gulp.watch('./src/less/**/*.less', ['less']);
});

const gulp = require('gulp'),
    rename = require('gulp-rename'),
    less = require('gulp-less'),
    pug = require('gulp-pug')
    argv = require('yargs').argv

/**
 * Compile less to css and minify
 */
gulp.task('less', function () {

    gulp.src('./src/less/**/*.less')
        .pipe(less({
            compress:true
        }))
        .pipe(gulp.dest('./src/css/'));

});

// Build and export template
gulp.task('export', function () {

    // Get argument
    if (!argv.template && !argv.t)
        return console.log("Please enter template name \"gulp export --template <templatename>\" ");

    // Set template name and file path
    const templateName = argv.template || argv.t;
    const mainFile = './templates/' + templateName + '/index.pug';
    const minify = (argv.minify)? false : true;

    console.log("Get main file : " + mainFile);

    // Start gulp
    return gulp.src(mainFile)
        .pipe(pug({
            pretty: minify
        }))
        .pipe(rename( templateName + '.xml'))
        .pipe(gulp.dest('./build'))
})

// Auto compile
gulp.task('autocompile', function () {
    gulp.watch('./src/less/**/*.less', ['less']);
});

Update gulp export support pretty


var app = {
    Profiles: null
}; // Let's namespace our app's functions in here.

(function($) {
    $().ready(function() {
        $('html').removeClass('no-js').addClass('js');

        // Return the current locale (found in the body attribute
        // as a data attribute).
        app.locale = $('body').data('locale');

        // Return a localized URL.
        app.localeUrl = function(url) {
            return '/' + app.locale + '/' + url.toString();
        };

        // Apply language change once another language is selected
        $('#language').change(function() {
            $('#language-switcher').submit();
        });

        //Main nav dropdown
        $('a.dropdown-toggle').click(function() {
            $('.dropdown-menu').toggle();
            $('i.icon-reorder').toggleClass('open');
        });

        if ($.browser.msie) {
            $('input, textarea').placeholder();
        }
    });
})(jQuery);

var app = {
    Profiles: null
}; // Let's namespace our app's functions in here.

(function($) {
    $().ready(function() {
        $('html').removeClass('no-js').addClass('js');

        // Return the current locale (found in the body attribute
        // as a data attribute).
        app.locale = $('body').data('locale');

        // Return a localized URL.
        app.localeUrl = function(url) {
            return '/' + app.locale + '/' + url.toString();
        };

        // Apply language change once another language is selected
        $('#language').change(function() {
            $('#language-switcher').submit();
        });

        //Main nav dropdown
        $('a.dropdown-toggle').click(function() {
            $('.dropdown-menu').toggle();
            $('i.icon-reorder').toggleClass('open');
        });

        $('input, textarea').placeholder();
    });
})(jQuery);

Remove unnecessary IE check for placeholder


import React, { Component } from 'react';
import { Link } from 'react-router';
import * as styles from './Menu.scss';

export default class Menu extends Component {
  render() {
    return (

Brancher

            <Link to='/usertree'>
Write Code
</Link>
            <Link to='/treeExamples'>
See Examples
</Link>

    );
  }
}

import React from 'react';
import { Link } from 'react-router';
import * as styles from './Menu.scss';

export default () => {
  return (

Brancher

          <Link to='/codeOptions'>
Write Code
</Link>
          <Link to='/treeExamples'>
See Examples
</Link>

  );
};

Change route for options menu


'use strict';

var gulp = require('gulp');
var watch = require('gulp-watch');
var batch = require('gulp-batch');
var jshint = require('gulp-jshint');
var lab = require('gulp-lab');

var jsfiles = ['**/*.js', '!node_modules/**/*.js'];
var testfiles = ['test/**/*.js'];

gulp.task('lint', function() {
  gulp.src(jsfiles)
  .pipe(jshint())
  .pipe(jshint.reporter('default'));
});

gulp.task('test', ['lint'], function() {
  gulp.src(testfiles)
  .pipe(lab());
});

gulp.task('watch', ['test'], function() {
  watch('**/*.js', batch(function(events, done) {
    gulp.start('test', done);
  }));
});

gulp.task('default', ['watch']);

Add watch as default gulp task


let promise = Promise.defer();
let recaptcha = null;

window.vueRecaptchaApiLoaded = () => {
  recaptcha = window.grecaptcha;
  promise.resolve(recaptcha);
};

export function getRecaptcha() {
  if(recaptcha !== null) {
    return Promise.resolve(recaptcha);
  }

  return promise.promise;
}

export function checkRecaptchaLoad() {
  if(window.hasOwnProperty('grecaptcha')) {
    window.vueRecaptchaApiLoaded();
  }
}

export function assertRecaptchaLoad() {
  if(recaptcha === null) {
    throw new Error('ReCAPTCHA has not been loaded');
  }
}

export function render(ele, key, options) {
  return getRecaptcha().then((recaptcha) => {
    let opts = Object.assign({}, { sitekey: key }, options);
    return recaptcha.render(ele, opts);
  });
}

export function reset(widgetId) {
  let args = [];

  if(arguments.length > 0) {
    if(widgetId === null) {
      return;
    } else {
      args = [widgetId];
    }
  }

  assertRecaptchaLoad();
  getRecaptcha.then((recaptcha) => {
    recaptcha.reset.apply(null, args);
  });
}

let promise = {};
let recaptcha = null;

promise.promise = new Promise((resolve) => {
  promise.resolve = resolve;
});

window.vueRecaptchaApiLoaded = () => {
  recaptcha = window.grecaptcha;
  promise.resolve(recaptcha);
};

export function getRecaptcha() {
  if(recaptcha !== null) {
    return Promise.resolve(recaptcha);
  }

  return promise.promise;
}

export function checkRecaptchaLoad() {
  if(window.hasOwnProperty('grecaptcha')) {
    window.vueRecaptchaApiLoaded();
  }
}

export function assertRecaptchaLoad() {
  if(recaptcha === null) {
    throw new Error('ReCAPTCHA has not been loaded');
  }
}

export function render(ele, key, options) {
  return getRecaptcha().then((recaptcha) => {
    let opts = Object.assign({}, { sitekey: key }, options);
    return recaptcha.render(ele, opts);
  });
}

export function reset(widgetId) {
  let args = [];

  if(arguments.length > 0) {
    if(widgetId === null) {
      return;
    } else {
      args = [widgetId];
    }
  }

  assertRecaptchaLoad();
  getRecaptcha.then((recaptcha) => {
    recaptcha.reset.apply(null, args);
  });
}

Update for no defer function in babel-runtime


'use strict';

const gulp = require('gulp');
const validator = require('.');

const ok = () => {
  let status = true;
  return gulp.src('./test/ok.html')
    .pipe(validator())
    .on('error', () => {
      status = false;
    })
    .on('end', () => {
      if (status === true) {
        return;
      }

      throw new Error('ok.html isn\'t ok');
    });
};

const ng = () => {
  let status = true;
  try {
    return gulp.src('./test/ng.html')
      .pipe(validator())
      .on('error', () => {
        status = false;
      })
      .on('end', () => {
        if (status === false) {
          return;
        }

        throw new Error('ng.html isn\'t ng');
      });
  } catch (error) {}
};

gulp.task('test', ok, ng);

'use strict';

const gulp = require('gulp');
const validator = require('.');

const ok = () => {
  let status = true;
  return gulp.src('./test/ok.html')
    .pipe(validator())
    .on('error', () => {
      status = false;
    })
    .on('end', () => {
      if (status === true) {
        return;
      }

      throw new Error('ok.html isn\'t ok');
    });
};

const ng = () => {
  let status = true;
  try {
    return gulp.src('./test/ng.html')
      .pipe(validator())
      .on('error', () => {
        status = false;
      })
      .on('end', () => {
        if (status === false) {
          return;
        }

        throw new Error('ng.html isn\'t ng');
      });
  } catch (error) {}
};

gulp.task('test', gulp.parallel(ok, ng));

Fix test task and run in parallel.


(function ($) {
  $(window).load(function(){
      window.hologram(document.getElementsByClassName('hologram-area')[0], {
          uploadUrl: Drupal.settings.Hologram.uploadUrl,
          onComplete: function(result){
              var response = result['response'];
              console.log(result['response'].text);
              var json = JSON.stringify(result['files']);
              $('input[name="field_image[und][0][value][image_json]"').val(json);
         },
          config: {
              uploader: '/hologram/upload'
          },
      });

      var store = window.hologram.store;

      store.subscribe(function(){
          var files = store.getState().files;
          var val = JSON.stringify(files);
          $('input[name="field_image[und][0][value][field][image_json]"').val(json);
      });
  });
})(jQuery);

(function ($) {
  $(window).load(function(){
      window.hologram(document.getElementsByClassName('hologram-area')[0], {
          uploadUrl: Drupal.settings.Hologram.uploadUrl,
          onComplete: function(result){
              var response = result['response'];
              var json = JSON.stringify(result['files']);
              $('input[name="field_image[und][0][value][image_json]"').val(json);
         },
          config: {
              uploader: '/hologram/upload'
          },
      });

      var store = window.hologram.store;

      store.subscribe(function(){
          var files = store.getState().files;
          var json = JSON.stringify(files);
          $('input[name="field_image[und][0][value][field][image_json]"').val(json);
      });
  });
})(jQuery);

Fix varriable name of json


/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of perseo-fe
 *
 * perseo-fe is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * perseo-fe is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with perseo-fe.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[contacto@tid.es]
 */
'use strict';

/**
 * Constant strings for header with incoming requests
 *
 */
module.exports = {
    SERVICE_HEADER: 'fiware-servicepath',
    TENANT_HEADER: 'fiware-service',
    CORRELATOR_HEADER: 'unica-correlator'
};

/*
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of perseo-fe
 *
 * perseo-fe is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * perseo-fe is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with perseo-fe.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[contacto@tid.es]
 */
'use strict';

/**
 * Constant strings for header with incoming requests
 *
 */
module.exports = {
    SERVICE_HEADER: 'fiware-servicepath',
    TENANT_HEADER: 'fiware-service',
    CORRELATOR_HEADER: 'unica-correlator',
    AUTH_HEADER: 'X-Auth-Token'
};

Add constant for auth field header (updateAction -> PEP)


var CronJob = require('cron').CronJob;

/**
 * Create cron job based on config
 * @param {Object} config Configuration object
 * @returns {*}
 */
module.exports = function (config) {
  return new CronJob(config.cronTime, config.onTick, config.onComplete, true, config.timezone);
};

var CronJob = require('cron').CronJob;

/**
 * Create cron job based on config
 * @param {Object} config Configuration object
 * @returns {*}
 */
module.exports = function (config) {
  return new CronJob(
    config.cronTime,
    config.onTick,
    config.onComplete,
    config.start || true,
    config.timezone,
    config.context
  );
};

Implement starting job by manual


import {GuideTitleStyle} from './constants';
import guideMark from './guide-mark';
import {TextMark} from '../marks/marktypes';
import {LegendTitleRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

export default function(spec, config, userEncode, dataRef) {
  var zero = {value: 0},
      title = spec.title,
      encode = {}, enter;

  encode.enter = enter = {
    x: {field: {group: 'padding'}},
    y: {field: {group: 'padding'}},
    opacity: zero
  };
  addEncode(enter, 'align', config.titleAlign);
  addEncode(enter, 'baseline', config.titleBaseline);
  addEncode(enter, 'fill', config.titleColor);
  addEncode(enter, 'font', config.titleFont);
  addEncode(enter, 'fontSize', config.titleFontSize);
  addEncode(enter, 'fontWeight', config.titleFontWeight);
  addEncode(enter, 'limit', config.titleLimit);

  encode.exit = {
    opacity: zero
  };

  encode.update = {
    opacity: {value: 1},
    text: title && title.signal ? {signal: title.signal} : {value: title + ''}
  };

  return guideMark(TextMark, LegendTitleRole, GuideTitleStyle, null, dataRef, encode, userEncode);
}

import {GuideTitleStyle} from './constants';
import guideMark from './guide-mark';
import {lookup} from './guide-util';
import {TextMark} from '../marks/marktypes';
import {LegendTitleRole} from '../marks/roles';
import {addEncode, encoder} from '../encode/encode-util';

export default function(spec, config, userEncode, dataRef) {
  var zero = {value: 0},
      encode = {}, enter;

  encode.enter = enter = {
    x: {field: {group: 'padding'}},
    y: {field: {group: 'padding'}},
    opacity: zero
  };
  addEncode(enter, 'align',      lookup('titleAlign', spec, config));
  addEncode(enter, 'baseline',   lookup('titleBaseline', spec, config));
  addEncode(enter, 'fill',       lookup('titleColor', spec, config));
  addEncode(enter, 'font',       lookup('titleFont', spec, config));
  addEncode(enter, 'fontSize',   lookup('titleFontSize', spec, config));
  addEncode(enter, 'fontWeight', lookup('titleFontWeight', spec, config));
  addEncode(enter, 'limit',      lookup('titleLimit', spec, config));

  encode.exit = {
    opacity: zero
  };

  encode.update = {
    opacity: {value: 1},
    text: encoder(spec.title)
  };

  return guideMark(TextMark, LegendTitleRole, GuideTitleStyle, null, dataRef, encode, userEncode);
}

Add configuration properties for legend title specifications.


"use strict";

Object.defineProperty(exports, "__esModule", { value: true });

const Lint = require("tslint");
// These files aren't part of the debug adapters and should probably be separated
// into another folder at some point.
const excludedPaths = ["src/debug/flutter_run.ts", "src/debug/flutter_test.ts"]

class Rule extends Lint.Rules.AbstractRule {
	apply(sourceFile) {
		if (sourceFile.fileName.indexOf("src/debug/") === 0 && excludedPaths.indexOf(sourceFile.fileName) === -1) {
			return this.applyWithWalker(new NoVsCodeInDebuggers(sourceFile, this.getOptions()));
		}
	}
}
Rule.FAILURE_STRING = "Do not import vscode into debug adapters as they may be run in a separate process to VS Code.";

class NoVsCodeInDebuggers extends Lint.RuleWalker {
	visitImportDeclaration(node) {
		if (node.moduleSpecifier.text === "vscode") {
			this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
		}
	}
}

exports.Rule = Rule;

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });

const Lint = require("tslint");
// These files aren't part of the debug adapters and should probably be separated
// into another folder at some point.
const excludedPaths = ["src/debug/flutter_run.ts", "src/debug/flutter_test.ts"]

class Rule extends Lint.Rules.AbstractRule {
	apply(sourceFile) {
		if (sourceFile.fileName.indexOf("src/debug/") !== -1 && excludedPaths.indexOf(sourceFile.fileName) === -1) {
			return this.applyWithWalker(new NoVsCodeInDebuggers(sourceFile, this.getOptions()));
		}
	}
}
Rule.FAILURE_STRING = "Do not import vscode into debug adapters as they may be run in a separate process to VS Code.";

class NoVsCodeInDebuggers extends Lint.RuleWalker {
	visitImportDeclaration(node) {
		if (node.moduleSpecifier.text === "vscode") {
			this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
		}
	}
}

exports.Rule = Rule;

Fix lint to work with absolute paths (tslint VS Code plugin)


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const jwt = require('jsonwebtoken');
const secretToken = require('../config').secretToken;
const validate = require('jsonschema').validate;

/**
 * Middleware function to force a route to require authentication
 * Verifies the request's token against the server's secret token
 */
module.exports = (req, res, next) => {
	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};
	if (!validate(token, validParams).valid) {
		res.sendStatus(400);
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				res.status(401).json({ success: false, message: 'Failed to authenticate token.' });
			}
			req.decoded = decoded;
			next();
		});
	} else {
		res.status(403).send({
			success: false,
			message: 'No token provided.'
		});
	}
};

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const jwt = require('jsonwebtoken');
const secretToken = require('../config').secretToken;
const validate = require('jsonschema').validate;

/**
 * Middleware function to force a route to require authentication
 * Verifies the request's token against the server's secret token
 */
module.exports = (req, res, next) => {
	const token = req.headers.token || req.body.token || req.query.token;
	const validParams = {
		type: 'string'
	};
	if (!validate(token, validParams).valid) {
		res.sendStatus(400);
	} else if (token) {
		jwt.verify(token, secretToken, (err, decoded) => {
			if (err) {
				res.status(401).json({ success: false, message: 'Failed to authenticate token.' });
			} else {
				req.decoded = decoded;
				next();
			}
		});
	} else {
		res.status(403).send({
			success: false,
			message: 'No token provided.'
		});
	}
};

Fix bug where auth would pass on after failure


const {ipcRenderer} = require('electron');

window.electron = {
    openExternal: function(url) {
        ipcRenderer.send('open-external', url);
    },
    notification: function(counter) {
        ipcRenderer.send('notification', 0 + counter);
    }
};

// shim for old Movim pods
window.require = function(str) {
    return {
        shell: {
            openExternal: function(url) {
                window.electron.openExternal(url);
            }
        },
        remote: {
            getCurrentWindow: function() {
                return {
                    notification: function(counter) {
                        window.electron.notification(counter);
                    }
                }
            }
        }
    };
};

const {ipcRenderer} = require('electron');

window.electron = {
    openExternal: function(url) {
        ipcRenderer.send('open-external', url);
    },
    notification: function(counter) {
        ipcRenderer.send('notification', ~~counter);
    }
};

// shim for old Movim pods
window.require = function(str) {
    return {
        shell: {
            openExternal: function(url) {
                window.electron.openExternal(url);
            }
        },
        remote: {
            getCurrentWindow: function() {
                return {
                    notification: function(counter) {
                        window.electron.notification(counter);
                    }
                }
            }
        }
    };
};

Fix notification counter when there's more than 100 notifications


(function () {
  'use strict';

  module.exports = function (gulp, plugins, config) {
    return function () {
      return plugins.vinylFs.src(config.patternsPath + '/**/*.icons.svg')
        .pipe(plugins.plumber({ errorHandler: plugins.notify.onError('Error: <%= error.message %>') }))
        .pipe(plugins.vinylFs.symlink(config.templatesPath, { relative: true }));
    };
  };
})();

(function () {
  'use strict';

  module.exports = function (gulp, plugins, config) {
    return function () {
      return plugins.vinylFs.src(config.patternsPath + '/**/*.icons*.svg')
        .pipe(plugins.plumber({ errorHandler: plugins.notify.onError('Error: <%= error.message %>') }))
        .pipe(plugins.vinylFs.symlink(config.templatesPath, { relative: true }));
    };
  };
})();

Include enterprise icons in build.


#!/usr/bin/env node

'use strict';

Error.stackTraceLimit = 30;

exports.root = __dirname;

// Executed once all application were loaded.
// Used to "attach" hooks for models etc.
/* exports.init = function (N) {}; */

if (!module.parent) {
  require('nodeca.core/lib/system/runner').bootstrap(exports);
}

#!/usr/bin/env node

'use strict';

Error.stackTraceLimit = 30;

exports.root = __dirname;

// Executed once all application were loaded.
// Used to "attach" hooks for models etc.
/* exports.init = function (N) {}; */

// disable orc at runtime to avoid segfaults,
// see https://github.com/lovell/sharp/issues/172#issuecomment-162800414
process.env.VIPS_NOVECTOR = 1;

if (!module.parent) {
  require('nodeca.core/lib/system/runner').bootstrap(exports);
}

Disable liborc at runtime when using sharp


"use strict";

const DefaultOptions = require('./DefaultOptions'),
    path = require('path'),
    _ = require('lodash'),
    fs = require('fs');

class OptionsParser {

    static parse() {
        var smildFile = null,
            packageJson = require(path.join(process.cwd(), 'package.json'));
        try {
            smildFile = require(path.join(process.cwd(), 'smildfile.js'));
        } catch (error) {
            smildFile = {};
        }
        return _.assign(DefaultOptions(smildFile.projectType), smildFile, {
            projectPackage: packageJson
        });
    }

    static parseTypescript() {
        return this.parseProjectFile('tsconfig.json');
    }

    static parseBabel() {
        return this.parseProjectFile('.babelrc');
    }

    static parseProjectFile(filename) {
        try {
            return JSON.parse(fs.readFileSync(path.join(process.cwd(), filename), 'utf8'));
        } catch (error) {
            return JSON.parse(fs.readFileSync(path.join(__dirname, '../', filename), 'utf8'));
        }
    }
}

module.exports = OptionsParser;

"use strict";

const DefaultOptions = require('./DefaultOptions'),
    path = require('path'),
    _ = require('lodash'),
    fs = require('fs');

class OptionsParser {

    static parse() {
        var smildFile = null,
            packageJson = {};
        try {
            packageJson = require(path.join(process.cwd(), 'package.json'));
        } catch (error) {
        }
        try {
            smildFile = require(path.join(process.cwd(), 'smildfile.js'));
        } catch (error) {
            smildFile = {};
        }
        return _.assign(DefaultOptions(smildFile.projectType), smildFile, {
            projectPackage: packageJson
        });
    }

    static parseTypescript() {
        return this.parseProjectFile('tsconfig.json');
    }

    static parseBabel() {
        return this.parseProjectFile('.babelrc');
    }

    static parseProjectFile(filename) {
        try {
            return JSON.parse(fs.readFileSync(path.join(process.cwd(), filename), 'utf8'));
        } catch (error) {
            return JSON.parse(fs.readFileSync(path.join(__dirname, '../', filename), 'utf8'));
        }
    }
}

module.exports = OptionsParser;

Fix package.json parsing when project is not initialized