import React from 'react';

class App extends React.Component {
	constructor(){
		super();
		this.state = { txt: ''};
		this.update = this.update.bind(this);
	}
	update(e){
		this.setState({txt: e.target.value});
	}
	render() {
		return(

				<Widget txt={this.state.txt} update={this.update} />
				<Widget txt={this.state.txt} update={this.update} />
				<Widget txt={this.state.txt} update={this.update} />
				<Widget txt={this.state.txt} update={this.update} />
				<Widget txt={this.state.txt} update={this.update} />

		)
	}
}

const Widget = (props) => {
	return (

			<input type="text" onChange={props.update}/>

{props.txt}

	)
};

export default App;

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
	constructor(){
		super();
		this.state = {
			red: 0,
			green: 0,
			blue: 0
		};
		this.update = this.update.bind(this);
	}
	update(e){
		this.setState({
			red: ReactDOM.findDOMNode(this.refs.red.refs.input).value,
			green: ReactDOM.findDOMNode(this.refs.green.refs.input).value,
			blue: ReactDOM.findDOMNode(this.refs.blue.refs.input).value
		});
	}
	render() {
		return(

				<Slider ref="red" update={this.update} />
				{this.state.red}
				<Slider ref="green" update={this.update} />
				{this.state.green}
				<Slider ref="blue" update={this.update} />
				{this.state.blue}

		)
	}
}

class Slider extends React.Component {
	render() {
		return (

				<input ref="input" type="range"
					min="0"
					max="255"
					onChange={this.props.update}/>

		);
	}
};

export default App;

Use refs to access child components


// Setup basic express server
var express = require('express');
var bodyParser = require('body-parser');
var debug = require('debug')('cloud');
var namespaces = require('./namespaces');

var app = express();

app.use(bodyParser.json());

app.post('/update', function(req,res) {
  var body = req.body;
  var type = body.type;
  debug('type is:' + type);
  var id = 'ns1';
  var payload = body.payload;
  debug('Payload is:' +payload);
  // TODO: error checks for invalid id, empty id, empty request -- and add unit tests

  var subDomain= req.hostname;
  debug('Domain is '  + subDomain);
  subDomain = subDomain.substring(0,subDomain.indexOf("."));
  debug('Sub Domain is '  + subDomain);
  var nsp = namespaces[id];
  //nsp.emit(type, payload);

  //console.dir(nsp);
  //debug(type + ' action had payload: ' + payload);

  var i;
  for ( i=0; i <nsp.sockets.length ; i++)
  {
	  var hostName = nsp.sockets[i].handshake.headers.host;
	  hostName = hostName.split(".")[0];
	  if ( hostName == subDomain)
	   {
		   debug("Emitting:" + payload);
		   nsp.sockets[i].emit(type,payload);
	   }
	   debug("Hostname and subdomain" + hostName + " " + subDomain);
  }

  res.json({
    payload: payload
  });

});

module.exports = app;

// Setup basic express server
var express = require('express');
var bodyParser = require('body-parser');
var debug = require('debug')('cloud');
var namespaces = require('./namespaces');

var app = express();

app.use(bodyParser.json());

app.post('/update', function(req,res) {
  var body = req.body;
  var type = body.type;
  debug('type is:' + type);
  var id = 'ns1';
  var payload = body.payload;
  debug('Payload is:' +payload);
  // TODO: error checks for invalid id, empty id, empty request -- and add unit tests

  var subDomain= req.hostname;
  debug('Domain is '  + subDomain);
  subDomain = subDomain.substring(0,subDomain.indexOf("."));
  debug('Sub Domain is '  + subDomain);
  var nsp = namespaces[id];
  //nsp.emit(type, payload);

  //console.dir(nsp);
  //debug(type + ' action had payload: ' + payload);

  var i;
  for ( i=0; i <nsp.sockets.length ; i++)
  {
	  var hostName = nsp.sockets[i].handshake.headers.host;
	  hostName = hostName.split(".")[0];
	  if ( hostName == subDomain)
	   {
		   debug("Emitting:" + payload);
		   nsp.sockets[i].compressData(true).emit(type,payload,"vishal");
	   }
	   debug("Hostname and subdomain" + hostName + " " + subDomain);
  }

  /*res.json({
    payload: payload
  });*/

});

module.exports = app;

Compress the payload in a basic manner to test


var program = require("commander");

program
  .version("0.0.1")
  .option("-s, --smtp-port [number]", "SMTP server port (1025 by default).")
  .option("-p, --http-port [number]", "HTTP server port (8080 by default).")
  .option("-q, --quite", "Do not dump mails to the console (false by default).")
  .option("-w, --whitelist [value]", "Aceppt mails from these adresses only (no whitelist by default).", collect, [])
  .option("-m --max [number]", "Max number of e-mails to keep (200 by default)")
  .parse(process.argv);

function collect(val, memory) {
  memory.push(val);
  return memory;
}

var config = {
	smtpPort: program.smtpPort || 1025,
	httpPort: program.httpPort || 8080,
	dumpFiles: program.dumpFiles || true,
	dumpDir: program.dumpDir || "./",
    whitelist: program.whitelist || [],
    quite: program.quite || false,
    maxEmails: program.max || 200
};

module.exports = {
	config: config
};

var program = require("commander");

program
  .version(getVersion())
  .option("-s, --smtp-port [number]", "SMTP server port (1025 by default).")
  .option("-p, --http-port [number]", "HTTP server port (8080 by default).")
  .option("-q, --quite", "Do not dump mails to the console (false by default).")
  .option("-w, --whitelist [value]", "Aceppt mails from these adresses only (no whitelist by default).", collect, [])
  .option("-m --max [number]", "Max number of e-mails to keep (200 by default)")
  .parse(process.argv);

function collect(val, memory) {
  memory.push(val);
  return memory;
}

/**
 * Returns the mail-sink version from package.json
 */
function getVersion() {
    return require("./package.json").version;
}

var config = {
	smtpPort: program.smtpPort || 1025,
	httpPort: program.httpPort || 8080,
	dumpFiles: program.dumpFiles || true,
	dumpDir: program.dumpDir || "./",
    whitelist: program.whitelist || [],
    quite: program.quite || false,
    maxEmails: program.max || 200
};

module.exports = {
	config: config
};

Read program version from package.json for -V flag


#!/usr/bin/env node

var args = process.argv;
var text = args[args.length - 1];

var encoder = require('./index.js');
console.log(encoder(text));

#!/usr/bin/env node

var args = process.argv;
var text = args[args.length - 1];

var encoder = require('./index.js');
process.stdout.write(encoder(text));

Change the console.log to stdout.write


var assert = chai.assert;

describe('react-frozenhead', function () {
    it('passes a test', function () {
        assert(true);
    });
});

var assert = chai.assert,
    html = React.DOM.html,
    title = React.DOM.title,
    FrozenHead = ReactFrozenHead;

var page = function (pageTitle) {
    return (
        html(null,
            FrozenHead(null,
                title(null, pageTitle)
            )
        )
    );
};

var App = React.createClass({
    getDefaultProps: function () {
        return {title: 'HOME'};
    },
    render: function () {
        return page(this.props.title);
    }
});

describe('react-frozenhead', function () {
    it('renders the initial title', function () {
        var app = App({title: 'INITIAL'}),
            html = React.renderComponentToString(app);
        assert.include(html, '<title>INITIAL</title>');
    });

    it("doesn't update the DOM title after mounting", function (done) {
        var container = document.createElement('div');
            app = React.renderComponent(App({title: 'INITIAL'}), container);
        app.setProps({title: 'NEW'}, function () {
            var titleEl = container.querySelector('title');
            assert.equal(titleEl.text, 'INITIAL');
            done();
        });
    });
});

Test that titles are updated as expected


// https://github.com/andywer/postcss-debug#js-code

/* eslint-disable strict, no-console */

'use strict';

const fs = require('fs');
const postcss = require('postcss');
const postcssrc = require('postcss-load-config');
const { createDebugger } = require('postcss-debug');

const debug = createDebugger();

const ctx = {
  map: { inline: false },
  from: './src/css/main.css',
  to: './lib/index.css',
};

const css = fs.readFileSync(ctx.from, 'utf8');

postcssrc(ctx).then(({ plugins, options }) => {
  postcss(debug(plugins))
    .process(css, options)
    .then((result) => {
      result.warnings().forEach((warn) => {
        process.stderr.write(`${warn.toString()}\n`);
      });

      if (result.map) {
        fs.writeFile(`${result.opts.to}.map`, result.map.toString());
      }

      debug.inspect();
      console.info('\n-----------------------------------------\n');
      console.info(plugins);
      console.info('\n-----------------------------------------\n');
      console.info(result);
    })
    .catch((error) => {
      if (error.name === 'CssSyntaxError') {
        process.stderr.write(error.message + error.showSourceCode());
      } else {
        throw error;
      }
    });
});

// https://github.com/andywer/postcss-debug#js-code

/* eslint-disable strict, no-console */

'use strict';

const fs = require('fs');
const postcss = require('postcss');
const postcssrc = require('postcss-load-config');
const { createDebugger } = require('postcss-debug');

const debug = createDebugger();

const ctx = {
  map: { inline: false },
  from: './packages/css/src/index.css',
  to: './packages/css/dist/index.css',
};

const css = fs.readFileSync(ctx.from, 'utf8');

postcssrc(ctx).then(({ plugins, options }) => {
  postcss(debug(plugins))
    .process(css, options)
    .then((result) => {
      result.warnings().forEach((warn) => {
        process.stderr.write(`${warn.toString()}\n`);
      });

      if (result.map) {
        fs.writeFile(`${result.opts.to}.map`, result.map.toString());
      }

      debug.inspect();
      console.info('\n-----------------------------------------\n');
      console.info(plugins);
      console.info('\n-----------------------------------------\n');
      console.info(result);
    })
    .catch((error) => {
      if (error.name === 'CssSyntaxError') {
        process.stderr.write(error.message + error.showSourceCode());
      } else {
        throw error;
      }
    });
});

Fix incorrect paths in postcss debugger


module.exports = function (config) {
  config.set({
    basePath: '.',
    frameworks: ['mocha'],
    reporters: ['mocha'],
    files: [
      '../node_modules/es6-promise/dist/es6-promise.js',
      './build/injector.js',
      './build/bundle.js'
    ],
    preprocessors: {
      'test/build/bundle.js': ['sourcemap']
    },
    port: 9876,
    colors: true,
    singleRun: true,
    logLevel: config.LOG_INFO
  });
};

module.exports = function (config) {
  config.set({
    basePath: '.',
    frameworks: ['mocha'],
    reporters: ['mocha'],
    client: {
      mocha: {
        timeout : 6000 // 6 seconds - upped from 2 seconds
      }
    },
    files: [
      '../node_modules/es6-promise/dist/es6-promise.js',
      './build/injector.js',
      './build/bundle.js'
    ],
    preprocessors: {
      'test/build/bundle.js': ['sourcemap']
    },
    port: 9876,
    colors: true,
    singleRun: true,
    logLevel: config.LOG_INFO
  });
};

Allow the mocha tests to take 6 seconds


var count = 1;

$(document).ready(function() {

  var b = $(".bottom-arrow");

  var u = $(".up-arrow");

  b.click(function(e) {
    if ($(".slide" + (+count + 1)).length) {
			count++;
      goToByScroll("slide" + count);

      b.html('▼');
			u.html('▲');
    } else {

		}

		if(!($(".slide" + (+count+1)).length)) {
      b.html('❭');
    }

  });
  u.click(function(e) {
    if (count > 1) {
      count--;
      goToByScroll("slide" + count);

			b.html('▼');
      u.html('▲');
    } else {

		}

		if (count == 1){
      u.html('➰');
    }
  });
})

var count = 1;

$(document).ready(function() {

  var b = $(".bottom-arrow");

  var u = $(".up-arrow");

  b.click(function(e) {
    if ($(".slide" + (+count + 1)).length) {
			count++;
      goToByScroll("slide" + count);

      b.html('▼');
			u.html('▲');
    } else {
			$("#submitnarrative").submit;
		}

		if(!($(".slide" + (+count+1)).length)) {
      b.html('❭');
    }

  });
  u.click(function(e) {
    if (count > 1) {
      count--;
      goToByScroll("slide" + count);

			b.html('▼');
      u.html('▲');
    } else {

		}

		if (count == 1){
      u.html('➰');
    }
  });
})

Add the submit function to the last button


angular.module("Prometheus.services").factory('UrlConfigDecoder', function($location) {
  return function(defaultHash) {
    var hash = $location.hash() || defaultHash;
    if (!hash) {
      return {};
    }
    var configJSON = atob(hash);
    var config = JSON.parse(configJSON);
    return config;
  };
});

angular.module("Prometheus.services").factory('UrlHashEncoder', ["UrlConfigDecoder", function(UrlConfigDecoder) {
  return function(config) {
    var urlConfig = UrlConfigDecoder();
    for (var o in config) {
      urlConfig[o] = config[o];
    }
    var configJSON = JSON.stringify(urlConfig);
    return btoa(configJSON);
  };
}]);

angular.module("Prometheus.services").factory('UrlConfigEncoder', ["$location", "UrlHashEncoder", function($location, UrlHashEncoder) {
  return function(config) {
    $location.hash(UrlHashEncoder(config));
  };
}]);

angular.module("Prometheus.services").factory('UrlVariablesDecoder', function($location) {
  return function() {
    return $location.search();
  };
});

angular.module("Prometheus.services").factory('UrlConfigDecoder', function($location) {
  return function(defaultHash) {
    var hash = $location.hash() || defaultHash;
    if (!hash) {
      return {};
    }
    // Decodes UTF-8
    // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64.btoa#Unicode_Strings
    var configJSON = unescape(decodeURIComponent(window.atob(hash)));
    var config = JSON.parse(configJSON);
    return config;
  };
});

angular.module("Prometheus.services").factory('UrlHashEncoder', ["UrlConfigDecoder", function(UrlConfigDecoder) {
  return function(config) {
    var urlConfig = UrlConfigDecoder();
    for (var o in config) {
      urlConfig[o] = config[o];
    }
    var configJSON = JSON.stringify(urlConfig);
    // Encodes UTF-8
    // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64.btoa#Unicode_Strings
    return window.btoa(encodeURIComponent(escape(configJSON)));
  };
}]);

angular.module("Prometheus.services").factory('UrlConfigEncoder', ["$location", "UrlHashEncoder", function($location, UrlHashEncoder) {
  return function(config) {
    $location.hash(UrlHashEncoder(config));
  };
}]);

angular.module("Prometheus.services").factory('UrlVariablesDecoder', function($location) {
  return function() {
    return $location.search();
  };
});

Support UTF-8 for encoding/decoding widget links.


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

module.exports = {
    'swagger': '2.0',
    'info': {
        'title': 'Koodilehto CRM API',
        'description': 'Manage your clients and invoices using Koodilehto CRM API',
        'version': '1.0.0'
    },
    'host': config.ip + ':' + config.port,
    'schemes': [
        'https'
    ],
    'basePath': '/v1',
    'produces': [
        'application/json'
    ],
    'paths': require('./paths'),
    'definitions': require('./definitions')
};

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

module.exports = {
    'swagger': '2.0',
    'info': {
        'title': 'Koodilehto CRM API',
        'description': 'Manage your clients and invoices using Koodilehto CRM API',
        'version': '1.0.0'
    },
    'host': config.ip + ':' + config.port,
    'schemes': [
        'http', // TODO: disable in production
        'https'
    ],
    'basePath': '/v1',
    'produces': [
        'application/json'
    ],
    'paths': require('./paths'),
    'definitions': require('./definitions')
};

Allow http scheme so that the demo client works


const Sequelize = require('sequelize');
const config = require('config');

const databaseConnection = new Sequelize(config.get('databaseUrl'), { //todo: configs here!
    dialect: 'postgres',
    protocol: 'postgres',
    dialectOptions: {
        ssl: config.get('usingSsl')
    }
});

databaseConnection
    .authenticate()
    .catch(err => {
        console.error('Unable to connect to the database:', err);
    });

databaseConnection.sync();

module.exports = databaseConnection;

const Sequelize = require('sequelize');
const config = require('config');

const databaseConnection = new Sequelize(config.get('databaseUrl'), { //todo: configs here!
    dialect: 'postgres',
    protocol: 'postgres',
    dialectOptions: {
        ssl: config.get('usingSsl')
    },
    logging: false
});

databaseConnection
    .authenticate()
    .catch(err => {
        console.error('Unable to connect to the database:', err);
    });

databaseConnection.sync();

module.exports = databaseConnection;

Remove console logging in database config.


describe('pingPongType', function() {
  it("returns ping for a number that is divisible by 3", function() {
    expect(pingPongType(6)).to.equal("ping");
  });
  it("returns pong for a number that is divisible by 5", function() {
    expect(pingPongType(10)).to.equal("pong");
  });
  it("returns pingpong for a number that is divisible by 3 and 5", function() {
    expect(pingPongType(30)).to.equal("pingpong")
  });
});

describe('isPingPong', function() {
  it("returns pingPongType for a number divisible by 3, 5, or 15", function() {
    expect(isPingPong(6)).to.equal("ping");
  });
  it("returns false for a number not divisible by 3, 5, or 15", function() {
    expect(isPingPong(7)).to.equal(false);
  });
});

describe('pingPongType', function() {
  it("returns ping for a number that is divisible by 3", function() {
    expect(pingPongType(6)).to.equal("ping");
  });
  it("returns pong for a number that is divisible by 5", function() {
    expect(pingPongType(10)).to.equal("pong");
  });
  it("returns pingpong for a number that is divisible by 3 and 5", function() {
    expect(pingPongType(30)).to.equal("pingpong")
  });
  it("returns an input number if the number is not divisble by 3 or 5", function() {
    expect(pingPongType(7)).to.equal(7);
  });
});

Remove description for isPingPong, update test for pingPongType according to new JavaScript code


// Dependencies
var nock = require('nock'),
   solr = require('./../main'),
   vows = require('vows'),
   assert = require('assert'),
   mocks = require('./mocks'),
   fs = require('fs');

// Load configuration file
var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'));

if(config.mocked){
   //nock.recorder.rec();
   mocks.facet(nock);
}

// Suite Test

var suite = vows.describe('Solr Client API: facet');

suite.addBatch({
   'Create a facet' : {
      'with the following options: `field`, `prefix`, `query`, `limit`, `offset`, `sort`, `limit`, `mincount`, `missing`, `method`' : {
         topic : function(){
            var client = solr.createClient();
            var query = client.createQuery()
                           .q({'*' : '*'})
                           .rows(0)
                           .facet({
                              field : 'title',
                              prefix : 'Ipa',
                              query : 'title:Ipad',
                              limit : 20,
                              offset : 0,
                              sort : 'count',
                              mincount : 0,
                              missing : false,
                              method : 'fc' ,
                           });
            client.search(query,this.callback);
         },
         'should return a correct response without error' :function(err,res) {
            assertCorrectResponse(err,res)
         }
      }
   }
}).export(module);

// Macro

function assertCorrectResponse(err,data){
   assert.isNull(err);
   assert.isObject(data);
   assert.equal(data.responseHeader.status,0);
}

// Dependencies
var nock = require('nock'),
   solr = require('./../main'),
   vows = require('vows'),
   assert = require('assert'),
   mocks = require('./mocks'),
   fs = require('fs');

// Load configuration file
var config = JSON.parse(fs.readFileSync(__dirname + '/config.json'));

if(config.mocked){
   //nock.recorder.rec();
   mocks.facet(nock);
}

// Suite Test

var suite = vows.describe('Solr Client API: facet');

suite.addBatch({
   'Create a facet' : {
      'with the following options: `field`, `prefix`, `query`, `limit`, `offset`, `sort`, `limit`, `mincount`, `missing`, `method`' : {
         topic : function(){
            var client = solr.createClient();
            var query = client.createQuery()
                           .q('*:*')
                           .rows(0)
                           .facet({
                              field : 'title',
                              prefix : 'Ipa',
                              query : 'title:Ipad',
                              limit : 20,
                              offset : 0,
                              sort : 'count',
                              mincount : 0,
                              missing : false,
                              method : 'fc' ,
                           });
            client.search(query,this.callback);
         },
         'should return a correct response without error' :function(err,res) {
            assertCorrectResponse(err,res)
         }
      }
   }
}).export(module);

// Macro

function assertCorrectResponse(err,data){
   assert.isNull(err);
   assert.isObject(data);
   assert.equal(data.responseHeader.status,0);
}

Use a string in `q` instead of an object because special characters in the values of each key of an object are now escaped as expected.


import mongoose from 'mongoose';

const { Schema } = mongoose;

const JourneySchema = new Schema({
  created: {
    type: Date,
    default: Date.now,
  },
  date: {
    type: Date,
    required: true,
  },
  description: {
    type: String,
    required: true,
  },
  lat: {
    type: Number,
    required: true,
  },
  lng: {
    type: Number,
    required: true,
  },
});

export default mongoose.model('Journey', JourneySchema);

import mongoose from 'mongoose';
import dateformat from 'dateformat';

const { Schema } = mongoose;

const JourneySchema = new Schema({
  created: {
    type: Date,
    default: Date.now,
  },
  date: {
    type: Date,
    required: true,
  },
  description: {
    type: String,
    required: true,
  },
  lat: {
    type: Number,
    required: true,
  },
  lng: {
    type: Number,
    required: true,
  },
}, {
  toObject: {
    virtuals: true,
  },
  toJSON: { virtuals: true },
});

JourneySchema.virtual('shortDate')
  .get(function shortDate() {
    return dateformat(this.date, 'dd.mm.yy');
  });

JourneySchema.virtual('inputDate')
  .get(function inputDate() {
    return dateformat(this.date, 'yyyy-mm-dd');
  })
  .set(function setInputDate(value) {
    console.log('setting input date');
    this.date = value;
  });

export default mongoose.model('Journey', JourneySchema);

Add formatted dates to journey schema


// FIXME works for View2D only

goog.provide('ol.interaction.KeyboardZoom');

goog.require('goog.events.KeyCodes');
goog.require('goog.events.KeyHandler.EventType');
goog.require('ol.View2D');
goog.require('ol.interaction.Interaction');

/**
 * @constructor
 * @extends {ol.interaction.Interaction}
 */
ol.interaction.KeyboardZoom = function() {
  goog.base(this);
};
goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);

/**
 * @inheritDoc
 */
ol.interaction.KeyboardZoom.prototype.handleMapBrowserEvent =
    function(mapBrowserEvent) {
  if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) {
    var keyEvent = /** @type {goog.events.KeyEvent} */
        (mapBrowserEvent.browserEvent);
    var charCode = keyEvent.charCode;
    if (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0)) {
      var map = mapBrowserEvent.map;
      var delta = (charCode == '+'.charCodeAt(0)) ? 4 : -4;
      // FIXME works for View2D only
      var view = map.getView();
      goog.asserts.assert(view instanceof ol.View2D);
      view.zoom(map, delta);
      keyEvent.preventDefault();
      mapBrowserEvent.preventDefault();
    }
  }
};

// FIXME works for View2D only

goog.provide('ol.interaction.KeyboardZoom');

goog.require('goog.events.KeyCodes');
goog.require('goog.events.KeyHandler.EventType');
goog.require('ol.View2D');
goog.require('ol.interaction.Interaction');

/**
 * @define {number} Zoom duration.
 */
ol.interaction.KEYBOARD_ZOOM_DURATION = 100;

/**
 * @constructor
 * @extends {ol.interaction.Interaction}
 */
ol.interaction.KeyboardZoom = function() {
  goog.base(this);
};
goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);

/**
 * @inheritDoc
 */
ol.interaction.KeyboardZoom.prototype.handleMapBrowserEvent =
    function(mapBrowserEvent) {
  if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) {
    var keyEvent = /** @type {goog.events.KeyEvent} */
        (mapBrowserEvent.browserEvent);
    var charCode = keyEvent.charCode;
    if (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0)) {
      var map = mapBrowserEvent.map;
      var delta = (charCode == '+'.charCodeAt(0)) ? 4 : -4;
      map.requestRenderFrame();
      // FIXME works for View2D only
      var view = map.getView();
      goog.asserts.assert(view instanceof ol.View2D);
      view.zoom(map, delta, undefined, ol.interaction.KEYBOARD_ZOOM_DURATION);
      keyEvent.preventDefault();
      mapBrowserEvent.preventDefault();
    }
  }
};

Add animated zoom to keyboard zoom interaction


import ConfigurableItemsPattern from './';
import ConfigurableItemsActions from './actions';
import Definition from './../../../demo/utils/definition';

let definition = new Definition('configurable-items-pattern', ConfigurableItemsPattern, {
  dataVariable: 'configurableItemsData',
  description: `A dialog that allows a list of items to be checked/unchecked and re-ordered.`,
  designerNotes: `
* Combines the ConfigurableItems and ConfigurableItemRow components.
  `,
  hiddenProps: ['itemsData'],
  propValues: {
    itemsData: `configurableItemsData`,
    onSave: `() => {}`,
    title: 'Configure Items'
  },
  propTypes: {
    className: 'String',
    itemsData: 'Object',
    onCancel: 'Function',
    onSave: 'Function',
    title: 'String'
  },
  propDescriptions: {
    itemsData: 'Data to define the items that can be configured',
    className : 'Classes to apply to the component.',
    onCancel: 'Callback triggered when the form is cancelled.',
    onSave: 'Callback triggered when the form is saved.',
    title: 'Title to display as heading'
  },
  relatedComponentsNotes: `
* [ConfigurableItems component](/components/configurable-items).
* [ConfigurableItemRow component](/components/configurable-items/configurable-item-row).
 `,
  requiredProps: ['onSave', 'title'],
});

definition.openPreview = true;
definition.onOpenPreview = function onOpenPreview() {
  ConfigurableItemsActions.toggleDialogOpen()
};

export default definition;

import ConfigurableItemsPattern from './';
import ConfigurableItemsActions from './actions';
import Definition from './../../../demo/utils/definition';

let definition = new Definition('configurable-items-pattern', ConfigurableItemsPattern, {
  dataVariable: 'configurableItemsData',
  description: `A dialog that allows a list of items to be checked/unchecked and re-ordered.`,
  designerNotes: `
* Combines the ConfigurableItems and ConfigurableItemRow components.
  `,
  hiddenProps: ['itemsData'],
  propValues: {
    itemsData: `configurableItemsData`,
    onSave: `configurableItemsOnSave`,
    title: 'Configure Items'
  },
  propTypes: {
    className: 'String',
    itemsData: 'Object',
    onCancel: 'Function',
    onSave: 'Function',
    title: 'String'
  },
  propDescriptions: {
    itemsData: 'Data to define the items that can be configured',
    className : 'Classes to apply to the component.',
    onCancel: 'Callback triggered when the form is cancelled.',
    onSave: 'Callback triggered when the form is saved.',
    title: 'Title to display as heading'
  },
  relatedComponentsNotes: `
* [ConfigurableItems component](/components/configurable-items).
* [ConfigurableItemRow component](/components/configurable-items/configurable-item-row).
 `,
  requiredProps: ['onSave', 'title'],
});

definition.openPreview = true;
definition.onOpenPreview = function onOpenPreview() {
  ConfigurableItemsActions.toggleDialogOpen()
};

global.configurableItemsOnSave = (event) => {
  event.preventDefault();
  ConfigurableItemsActions.toggleDialogOpen()
}

export default definition;

Update ConfigurableItems demo to not refresh page onSave


Package.describe({
  summary: "Retry logic with exponential backoff",
  internal: true
});

Package.on_use(function (api) {
  api.use('underscore', ['client', 'server']);
  api.export('Retry');
  api.add_files('retry.js', ['client', 'server']);
});

Package.describe({
  summary: "Retry logic with exponential backoff",
  internal: true
});

Package.on_use(function (api) {
  api.use(['underscore', 'random'], ['client', 'server']);
  api.export('Retry');
  api.add_files('retry.js', ['client', 'server']);
});

Add missing 'random' dependency to retry


/**
 * The default controller for your page structure.
 */
var turnpike = require('turnpike');
var util     = require('util');
var _        = turnpike._;

function Page(connection) {
  var $this = this;
  turnpike.classes.base.controller.EndpointController.call(this, connection);

  //TODO: Should we send error if we get here and the content type isn't HTML?
  this.deliver = function() {
    var view = new turnpike.application.views.Page();
    view.mode('main').data($this.data)
      .render(function(html) {
        connection.response(html).send();
      });
  };
}
util.inherits(Page, turnpike.classes.base.controller.EndpointController);

Page.prototype._GET =
Page.prototype._PUT =
Page.prototype._POST =
Page.prototype._DELETE = function(readyCallback) {
  this.data = {
    'body':  this.connection.response(),
    'title': this.connection.controller.title
  };

  process.nextTick(readyCallback);
};

module.exports = Page;

/**
 * The default controller for your page structure.
 */
var turnpike = require('turnpike');
var util     = require('util');
var _        = turnpike.imports.underscore;

function Page(connection) {
  var $this = this;
  turnpike.classes.base.controller.EndpointController.call(this, connection);

  //TODO: Should we send error if we get here and the content type isn't HTML?
  this.deliver = function() {
    var view = new turnpike.application.views.Page();
    view.mode('main').data($this.data)
      .render(function(html) {
        connection.response(html).send();
      });
  };
}
util.inherits(Page, turnpike.classes.base.controller.EndpointController);

Page.prototype._GET =
Page.prototype._PUT =
Page.prototype._POST =
Page.prototype._DELETE = function(readyCallback) {
  this.data = {
    'body':  this.connection.response(),
    'title': this.connection.controller.title
  };

  process.nextTick(readyCallback);
};

module.exports = Page;

Fix reference to exported version of underscore in project skeleton


import THREE from 'three';

const maps = {
  minimal( scene ) {
    const geometry = new THREE.IcosahedronGeometry( 1, 2 );
    const material = new THREE.MeshPhongMaterial({
      shading: THREE.FlatShading
    });

    const mesh = new THREE.Mesh( geometry, material );
    mesh.position.set( 0, 0, -8 );
    scene.add( mesh );

    const light = new THREE.PointLight();
    light.position.set( 8, 8, 8 );
    scene.add( light );

    scene.add( new THREE.HemisphereLight( '#f43', '#33a', 0.5 ) );
  }
};

export default function createMap( scene, name ) {
  maps[ name ]( scene );
}

import THREE from 'three';

function createAsteroidMesh( x, y, z, radius ) {
  const geometry = new THREE.IcosahedronGeometry( radius, 2 );
  const material = new THREE.MeshPhongMaterial({
    shading: THREE.FlatShading
  });

  const mesh = new THREE.Mesh( geometry, material );
  mesh.position.set( x, y, z );
  return mesh;
}

function createAsteroidMeshes( asteroids ) {
  return asteroids.map( asteroid => createAsteroidMesh( ...asteroid ) );
}

const maps = {
  minimal( scene ) {
    const meshes = createAsteroidMeshes([
      [ 0, 0, -8, 1 ],
      [ 4, -2, -4, 2 ]
    ]);

    scene.add( ...meshes );

    const light = new THREE.PointLight();
    light.position.set( 8, 8, 8 );
    scene.add( light );

    scene.add( new THREE.HemisphereLight( '#f43', '#33a', 0.5 ) );
  }
};

export default function createMap( scene, name ) {
  maps[ name ]( scene );
}

Generalize test scene geometry generation.


import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';

export default class App extends Application {
  modulePrefix = config.modulePrefix;
  podModulePrefix = config.podModulePrefix;
  Resolver = Resolver;
}

loadInitializers(App, config.modulePrefix);

import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';

const App = Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver
});

loadInitializers(App, config.modulePrefix);

export default App;

Fix a11y testing for older Ember versions


import template from 'babel-template';

export default str => {
    return template(str, {sourceType: 'module'});
};

import template from 'babel-template';

export default (str, opts = {}) => {
    return template(str, {
        ...opts,
        sourceType: 'module',
    });
};

Update template wrapper to support preserveComments.


'use strict';

/**
 * @ngdoc directive
 * @name angular-uploadcare.directive:Uploadcare
 * @description Provides a directive for the Uploadcare widget.
 * # Uploadcare
 */
angular.module('ng-uploadcare', [])
  .directive('uploadcareWidget', function () {
    return {
      restrict: 'A',
      require: 'ngModel',
      scope: {
        onWidgetReady: '&',
        onUploadComplete: '&',
        onChange: '&',
      },
      controller: ['$scope', '$element', '$attrs', '$parse', '$log', function($scope, $element, $attrs, $parse, $log) {
        if(!uploadcare) {
          $log.error('Uploadcare script has not been loaded!.');
          return;
        }
        $element.attr('type', 'hidden');
        $scope.widget = uploadcare.Widget($element);
        $scope.onWidgetReady({widget: $scope.widget});
        $scope.widget.onUploadComplete(function(info) {
          $scope.onUploadComplete({info: info});
        });
        $scope.widget.onChange(function(file) {
          // add data binding for hidden inputs
          $scope.$apply(function () {
            $parse($attrs.ngModel).assign($scope.$parent, $element.val());
          });
          $scope.onChange({file: file});
        })
      }]
    };
  });

'use strict';

/**
 * @ngdoc directive
 * @name angular-uploadcare.directive:Uploadcare
 * @description Provides a directive for the Uploadcare widget.
 * # Uploadcare
 */
angular.module('ng-uploadcare', [])
  .directive('uploadcareWidget', function () {
    return {
      restrict: 'A',
      require: 'ngModel',
      scope: {
        onWidgetReady: '&',
        onUploadComplete: '&',
        onChange: '&',
        ngModel: '='
      },
      controller: ['$scope', '$element', '$attrs', '$log', function($scope, $element, $attrs, $log) {
        if(!uploadcare) {
          $log.error('Uploadcare script has not been loaded!.');
          return;
        }
        $element.attr('type', 'hidden');
        $scope.widget = uploadcare.Widget($element);
        $scope.onWidgetReady({widget: $scope.widget});
        $scope.widget.onUploadComplete(function(info) {
          $scope.onUploadComplete({info: info});
        });
        $scope.widget.onChange(function(fileOrGroup) {
          // add data binding for hidden inputs
          if (fileOrGroup) {
            fileOrGroup.promise().done(function(info) {
              $scope.$apply(function () {
                $scope.ngModel = $element.val()
              });
            });
          }
          $scope.onChange({file: fileOrGroup});
        })
      }]
    };
  });

Fix issue with multiple files upload


"use strict";
let fetch = require('node-fetch');
module.exports = function searchDeclaration(link) {
    return fetch(link)
        .then(response => response.text())
        .then(data => JSON.parse(data))
        .catch((err) => {
            console.log(err);
            console.log("...But, I gotta keep trying, and never give up!");
            return module.exports(link);
        })
};

"use strict";
let fetch = require('node-fetch');
const _ = require("lodash");
module.exports = function searchDeclaration(link) {
    return fetch(link)
        .then(response => response.text())
        .then(data => {
            // Error may occurs
            /*
             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

             <meta http-equiv="content-type" content="text/html; charset=utf-8" />
             <meta http-equiv="content-language" content="uk" />
             <meta name="robots" content="noindex,nofollow,noarchive,nosnippet" />
             <title>504: Шлюз не відповідає</title>

504 Шлюз не відповідає

             */
            if (_.contains(data, "Шлюз не відповідає")) {
                return module.exports(link);
            }
            return JSON.parse(data)
        })
        .catch((err) => {
            console.log(err);
            console.log("...But, I gotta keep trying, and never give up!");
            return module.exports(link);
        })
}
;

Fix SyntaxError: Unexpected token < during scrapping


var Account = require('../../app/models/account');

exports.update = function (req, res) {
    Account.findById(req.params.id, function (err, account) {
        if (!account)
            return next(new Error('Could not load Document'));
        else {
            if (req.body.foreName) {
                account.foreName = req.body.foreName
            }
            if (req.body.sureName) {
                account.sureName = req.body.sureName
            }
            if (req.body.phoneNumber) {
                account.phoneNumber = req.body.phoneNumber
            }

            account.save(function (err) {
                if (err)
                    res.json({ message: 'Error' });
                else
                    res.json({ message: 'Account Updated' });
            });
        }
    });
}

var Account = require('../../app/models/account');

exports.update = function (req, res) {
    Account.findById(req.params.id, function (err, account) {
        if (!account)
            return next(new Error('Could not load Document'));
        else {
            if (req.body.foreName) {
                account.foreName = req.body.foreName
            }
            if (req.body.sureName) {
                account.sureName = req.body.sureName
            }
            if (req.body.phoneNumber) {
                account.phoneNumber = req.body.phoneNumber
            }

            account.save(function (err) {
                if (err)
                    res.json({ message: 'Error' });
                else
                    res.json(account);
            });
        }
    });
}

Update now returns the account info


module.exports = {
    extends: ["eslint:recommended", "prettier"],
    root: true,
    env: {
        es6: "true",
        browser: true,
        node: true,
        jest: true,
    },
    parser: "@babel/eslint-parser",
    ignorePatterns: ["dist/", "docs/", "node_modules/"],
    rules: {
        "no-debugger": 1,
        "no-duplicate-imports": 1,
        // Do keep due avoid unintendet consequences.
        "no-alert": 0,
        "no-control-regex": 0,
        "no-self-assign": 0,
        "no-useless-escape": 0,
    },
    globals: {},
};

Extend eslint config from @patternslib/dev.


function applyChanges(data, url, showResult) {
	var success = false;
	$.ajax({
		type : "POST",
		url : url,
		data : JSON.stringify(data),// now data come in this function
		contentType : "application/json; charset=utf-8",
		crossDomain : true,
		dataType : "json",
		success : function(data, status, jqXHR) {
			console.log("Applied changes successfully.")
			if (showResult) {
				var modal = $("#modal_success");
				modal.find('.modal-body p').text("Applied changes successfully");
				modal.modal('show');
			}
		},

		error : function(jqXHR, status) {
			console.log(jqXHR);
			var modal = $("#modal_error");
			modal.find('.modal-body p').text(jqXHR["responseText"]);
			modal.modal('show');
		}
	});

}

function getTableData(table) {
	var rData = []

	// reformat - pretty format
	var records = []
	table.rows().every(function() {
		var r = this.data();
		var record = {}
		record["record_name"] = r[0].trim();
		record["record_type"] = r[1].trim();
		record["record_status"] = r[2].trim();
		record["record_ttl"] = r[3].trim();
		record["record_data"] = r[4].trim();
		records.push(record);
	});
	return records
}

Add 'getDataTable' function from old template.


angular.module('anol.layerswitcher', [])

.directive('anolLayerswitcher', ['LayersService', function(LayersService) {
    return {
        restrict: 'A',
        transclude: true,
        templateUrl: 'anol/modules/layerswitcher/templates/layerswitcher.html',
        scope: {},
        link: function(scope, element, attrs) {
            scope.$watch('backgroundLayer', function(newVal, oldVal) {
                oldVal.setVisible(false);
                newVal.setVisible(true);
            });
        },
        controller: function($scope, $element, $attrs) {
            $scope.backgroundLayers = LayersService.backgroundLayers;
            angular.forEach($scope.backgroundLayers, function(layer) {
                if(layer.getVisible() === true) {
                    if($scope.backgroundLayer !== undefined) {
                        $scope.backgroundLayer.setVisible(false);
                    }
                    $scope.backgroundLayer = layer;
                }
            });
            $scope.overlayLayers = LayersService.overlayLayers;
        }
    };
}]);

angular.module('anol.layerswitcher', [])

.directive('anolLayerswitcher', ['LayersService', function(LayersService) {
    return {
        restrict: 'A',
        transclude: true,
        templateUrl: 'anol/modules/layerswitcher/templates/layerswitcher.html',
        scope: {},
        link: function(scope, element, attrs) {
            scope.$watch('backgroundLayer', function(newVal, oldVal) {
                oldVal.setVisible(false);
                newVal.setVisible(true);
            });
        },
        controller: function($scope, $element, $attrs) {
            $scope.backgroundLayers = LayersService.backgroundLayers;
            angular.forEach($scope.backgroundLayers, function(layer) {
                if(layer.getVisible() === true && $scope.backgroundLayer === undefined) {
                    $scope.backgroundLayer = layer;
                    $scope.backgroundLayer.setVisible(false);
                } else {
                    layer.setVisible(false);
                }
            });
            $scope.overlayLayers = LayersService.overlayLayers;
        }
    };
}]);

Use first visible background layer as active background layer


//var Teachers = require('../models/teachers');
//var TeacherClasses = require('../models/Teacher_classes');
//var Classes = require('../models/classes');
//var ClassLessons = require('../models/class_lessons');
// var Lessons = require('../models/lessons');
//var RequestedResponses = require('../models/requested_responses');

module.exports = {

  readyStage : function(io, req, res, next) {

    io.on('connection', function(student){
      student.emit('studentStandby', studentInformation);
    });

    res.status(200).send('Hello from the student side');
  }
};

//var Teachers = require('../models/teachers');
//var TeacherClasses = require('../models/Teacher_classes');
//var Classes = require('../models/classes');
//var ClassLessons = require('../models/class_lessons');
// var Lessons = require('../models/lessons');
//var RequestedResponses = require('../models/requested_responses');

module.exports = {

  readyStage : function(io, req, res, next) {

    io.on('connection', function(student){
      student.emit('studentStandby', studentInformation);
    });

    res.status(201).send('Welcome, student.');
  }
};

Send 201 status with student greeting


class Foo {
  constructor(a = 10, ...b) {
    this.a = a
    this.b = b
  }

  method() { return this.a + this.b }

  get x() { return `template${this.a}` }
}

let x = 1

const y = {
  func() { return 10 },
  get b() { return false },
  ["foo" + "bar"]: 800
}

let it = function*(n) {
  for (let i = 0; i < n; i++) yield n
}

console.log([for (a of [1, 2, ...it(10)]) a * 2])

let [a, b] = [1, 2];

let x = ([a], {b}) => a + b

let [e1,,e3] = ["5", false, 6]

const obj = {
  hi: 'hello'
};

const newObj = {
  hi,
  ...o //+
}
const {
  hi,
  ...o  //+
} = obj  //+ obj

Add simple test case for spread, rest syntax


'use strict';

var assert = require('assert');
var sinon = require('sinon');

var Customer = require('../../lib/endpoints/customer');
var Request = require('../../lib/request');

describe('endpoints/customer', function () {
    describe('contactInfo', function () {
        it('should set the request URL', function () {
            var request = new Request();
            var customer;
            var stub;

            stub = sinon.stub(request, 'post', function (url) {
                assert.strictEqual(url, '/customer/contactinfo');
            });

            customer = new Customer(request);
            customer.contactInfo();

            assert.ok(stub.called);
        });

        it('should set the request body', function () {
            var request = new Request();
            var customer;
            var stub;
            var expected = {
                companyname: 'companyname',
            };

            stub = sinon.stub(request, 'post', function (url, data) {
                assert.deepEqual(data, expected);
            });

            customer = new Customer(request);
            customer.contactInfo(expected);

            assert.ok(stub.called);
        });
    });
});

'use strict';

const assert = require('assert');
const sinon = require('sinon');

const Customer = require('../../lib/endpoints/customer');
const Request = require('../../lib/request');

describe('endpoints/customer', () => {
    describe('contactInfo', () => {
        it('should set the request URL', () => {
            const request = new Request();
            const customer = new Customer(request);
            const stub = sinon.stub(request, 'post', (url) => {
                assert.strictEqual(url, '/customer/contactinfo');
            });

            customer.contactInfo();

            assert.ok(stub.called);
        });

        it('should set the request body', () => {
            const request = new Request();
            const customer = new Customer(request);
            const expected = {
                companyname: 'companyname',
            };

            const stub = sinon.stub(request, 'post', (url, data) => {
                assert.deepEqual(data, expected);
            });

            customer.contactInfo(expected);

            assert.ok(stub.called);
        });
    });
});

Rewrite Customer tests to ES2015


'use strict';

var React = require('react/addons');
var _ = require('underscore');

/*
   Choices drop down component for picking tags.
 */
var ChoicesDropdown = React.createClass({
  handleClick: function (key) {
    this.props.handleSelection(key);
  },

  render: function() {
    var self = this;

    var items = _.map(this.props.choices, function (value, key) {
      var clickHandler = self.handleClick.bind(self, key);
      return (

          {value} | {key}

      );
    });

    return (

        <button className="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
          Insert...

        </button>

          {items}

    );
  }
});

module.exports = ChoicesDropdown;

'use strict';

var React = require('react/addons');
var _ = require('underscore');

/*
   Choices drop down component for picking tags.
 */
var ChoicesDropdown = React.createClass({
  handleClick: function (key) {
    this.props.handleSelection(key);
  },

  render: function() {
    var self = this;
    var items = [];
    var index = 0;
    var choices = this.props.choices;
    var len = Object.keys(choices).length;

    _.each(choices, function (value, key) {
      index++;
      var clickHandler = self.handleClick.bind(self, key);

      items.push(

          {value} | {key}

      );

      if (index < len) {
        var dividerKey = '_' + index; // squelch React warning about needing a key
        items.push(
);
      }
    });

    return (

        Insert...

          {items}

    );
  }
});

module.exports = ChoicesDropdown;

Change pretty-text2 choices dropdown to look like a link instead of a button


var $ = require('jQuery');
var onReady = require('kwf/on-ready');
var cookieOpt = require('kwf/cookie-opt');

onReady.onRender('.kwcClass', function (el, config) {
    cookieOpt.load(function(api) {
        if (!api.getCookieIsSet()) {
            if (config.showBanner) {
                $('body').addClass('kwfUp-showCookieBanner');
                onReady.callOnContentReady($('body'), { action: 'widthChange' });
            }
            el.show();
            el.find('.kwcBem__accept').click(function(e) {
                e.preventDefault();
                api.setOpt('in');
                el.hide();
                $('body').removeClass('kwfUp-showCookieBanner').addClass('kwfUp-cookieAccepted');
                onReady.callOnContentReady($('body'), { action: 'widthChange' });
            });
        }
        api.onOptChanged(function (value) {
            $('body').find('.kwcClass').hide();
        });
    });
});

var $ = require('jQuery');
var onReady = require('kwf/on-ready');
var cookieOpt = require('kwf/cookie-opt');
var statistics = require('kwf/statistics');

onReady.onRender('.kwcClass', function (el, config) {
    cookieOpt.load(function(api) {
        if (!api.getCookieIsSet()) {
            if (config.showBanner) {
                $('body').addClass('kwfUp-showCookieBanner');
                onReady.callOnContentReady($('body'), { action: 'widthChange' });
            }
            el.show();
            el.find('.kwcBem__accept').click(function(e) {
                e.preventDefault();
                api.setOpt('in');
                statistics.trackEvent('Cookies', location.pathname, 'Click on Accept in Cookie Banner');
                el.hide();
                $('body').removeClass('kwfUp-showCookieBanner').addClass('kwfUp-cookieAccepted');
                onReady.callOnContentReady($('body'), { action: 'widthChange' });
            });
        }
        api.onOptChanged(function (value) {
            $('body').find('.kwcClass').hide();
        });
    });
});

Add tracking event when clicking on Cookie Accept Button


import { connect } from 'react-redux';

import CommentList from './CommentList';

const getVisibleComments = (comments, currentTime) => {
  return comments
    .filter((streamedComment) => (streamedComment.time <= currentTime))
    .map((streamedComment) => (streamedComment.comment));
};

const mapStateToProps = (state) => {
  return {
    comments: getVisibleComments(state.commentStream, state.videoContainer.currentTime),
  };
};

const CommentStream = connect(
  mapStateToProps
)(CommentList);

export default CommentStream;

import { connect } from 'react-redux';

import CommentList from './CommentList';

const getVisibleComments = (comments, currentTime) => {
  return comments
    .filter((streamedComment) => (currentTime >= streamedComment.time))
    .map((streamedComment) => (streamedComment.comment));
};

const mapStateToProps = (state) => {
  return {
    comments: getVisibleComments(state.commentStream, state.videoContainer.currentTime),
  };
};

const CommentStream = connect(
  mapStateToProps
)(CommentList);

export default CommentStream;

Change the order of the conditional for clarity


var HTML = {

    createFeed: function(data) {
        var $clone = $('.template.feed').clone(true);
        $clone.removeClass('template');
        $clone.find('.title').text(data.title);
        $clone.find('.url').attr('href', data.url).text(data.url);
        return $clone;
    },

    createEntry: function(data) {
        var $clone = $('.template.news').clone(true);
        $clone.removeClass('template');
        $clone.find('.title').text(data.title);
        $clone.find('.url').attr('href', data.url).text(data.url);
        return $clone;
    },

    createTag: function(data) {
        var $clone = $('.template.tag').clone(true);
        $clone.removeClass('template');
        $clone.find('.title').text(data.title);
        $clone.find('.badge').text(data.entry_count);
        return $clone;
    }

};

var HTML = {

    createFeed: function(data) {
        var $clone = $('.template.feed').clone(true);
        $clone.data('modelId', data.id);
        $clone.removeClass('template');
        $clone.find('.title').text(data.title);
        $clone.find('.url').attr('href', data.url).text(data.url);
        return $clone;
    },

    createEntry: function(data) {
        var $clone = $('.template.news').clone(true);
        $clone.removeClass('template');
        $clone.find('.title').text(data.title);
        $clone.find('.url').attr('href', data.url).text(data.url);
        return $clone;
    },

    createTag: function(data) {
        var $clone = $('.template.tag').clone(true);
        $clone.removeClass('template');
        $clone.find('.title').text(data.title);
        $clone.find('.badge').text(data.entry_count);
        return $clone;
    }

};

Set modelId data attribute for feeds


const Jetpack = require('fs-jetpack');

/** File name to look for configuration */
const CONFIG_FILE_NAME = '.reconrc';

/**
 * Generate a full config for a working directory and any user config
 * - Will manage any sensible merging of configs as complexity grows
 */
function createConfig(uc, {cwd = process.cwd()} = {}) {
  // TODO: Search for definition within package.json
  const rc = Jetpack.cwd(cwd).read(CONFIG_FILE_NAME, 'json');
  if (!rc) {
    throw new Error('Oops! Doesn\'t look like there is a valid .reconrc file defined in your project root.');
  }
  return Object.assign({}, rc, uc);
}

module.exports = createConfig;

const Jetpack = require('fs-jetpack');

/** File name to look for configuration */
const CONFIG_FILE_NAME = '.reconrc';

/**
 * Generate a full config for a working directory and any user config
 * - Will manage any sensible merging of configs as complexity grows
 */
function createConfig(uc, {cwd = process.cwd()} = {}) {
  // TODO: Search for definition within package.json
  const rc = Jetpack.cwd(cwd).read(CONFIG_FILE_NAME, 'json');
  if (!rc) {
    throw new Error('Oops! Doesn\'t look like there is a valid .reconrc file defined in your project root. See: https://github.com/lystable/recon/tree/master/packages/recon-config for info.');
  }
  return Object.assign({}, rc, uc);
}

module.exports = createConfig;

Add link to config documentation


import _ from '../wrap/lodash'

import tdFunction from '../function'
import isGenerator from './is-generator'

export default (original, names) => {
  if (_.isArray(original) || _.isArguments(original)) {
    return []
  } else if (_.isFunction(original)) {
    if (isGenerator(original)) {
      return original
    } else {
      // TODO: this will become src/function/create and include parent reference instead of name joining here
      return tdFunction(names.map(String).join('') || '(anonymous function)')
    }
  } else {
    return _.clone(original)
  }
}

import _ from '../wrap/lodash'

import tdFunction from '../function'
import isGenerator from './is-generator'

export default (original, names) => {
  if (_.isArray(original) || _.isArguments(original)) {
    return []
  } else if (_.isFunction(original)) {
    if (isGenerator(original)) {
      return original
    } else {
      // TODO: this will become src/function/create and include parent reference instead of name joining here
      return tdFunction(_.map(names, String).join('') || '(anonymous function)')
    }
  } else {
    return _.clone(original)
  }
}

Use lodash.map wrapper instead of native [].map


const _ = require("lodash");
const express = require("express");
const router = express.Router();
const connect = require("../../utils/database.js");

// Route: {root}/api/users/...

// GET routes
// GET self

// Everything else should be restricted
// GET all users
router.get("/", function(req, res){
	// ALERT: Don't expose the hash!! ------------------------------------------------------------
	connect.then(function(db){
		return db.collection("_users_auth").find().toArray();
	}).then(function(data){
		res.json(data);
	});
});

// GET specific user
router.get("/:username", function(req, res){
	connect.then(function(db){
		return db.collection("_users_auth").findOne({username: req.params.username});
	}).then(function(data){
		res.json(data);
	});
});

// POST routes
// POST to create a new user
router.post("/", function(req, res){
	res.json({
		message: "Implementation pending"
	});
});

// POST to a user (edit existing user)
router.post("/:username", function(){
	res.json({
		message: "Implementation pending"
	});
});

// DELETE routes
// DELETE specific user
router.post("/:username", function(){
	res.json({
		message: "Implementation pending"
	});
});

module.exports = router;

const _ = require("lodash");
const express = require("express");
const router = express.Router();
const connect = require("../../utils/database.js");

// Route: {root}/api/users/...

// GET routes
// GET self

// Everything else should be restricted
// GET all users
router.get("/", function(req, res){
	connect.then(function(db){
		return db.collection("_users_auth").find().toArray();
	}).then(function(data){
		// Remove internal ID and password hash, maybe split the db later
		_.each(data, function(el, i){
			delete el._id;
			delete el.hash;
		});
		res.json(data);
	});
});

// GET specific user
router.get("/:username", function(req, res){
	connect.then(function(db){
		return db.collection("_users_auth").findOne({username: req.params.username});
	}).then(function(data){
		// Remove internal ID and password hash, maybe split the db later
		delete data._id;
		delete data.hash;
		res.json(data);
	});
});

// POST routes
// POST to create a new user
router.post("/", function(req, res){
	res.json({
		message: "Implementation pending"
	});
});

// POST to a user (edit existing user)
router.post("/:username", function(){
	res.json({
		message: "Implementation pending"
	});
});

// DELETE routes
// DELETE specific user
router.post("/:username", function(){
	res.json({
		message: "Implementation pending"
	});
});

module.exports = router;

Remove sensitive data from returned user data


import {exec} from 'child_process';
import {isAbsolute} from 'path';

function launch(path, options = {}) {
  if(!isAbsolute(path)) {
    return new Error('Application path "%s" is not absolute.', path);
  }
  if(!options instanceof Object) {
    return new Error('Option passed to launch must be an instance of Object, got ', typeof options);
  }

  if(!options.detached instanceof Boolean) {
    return new Error('Option key \'detached\' must an instance of Boolean, got ', typeof options.detached);
  }

  return exec(path, {detached: options.detached || true}, (err, stdout, stderr) => {
    if(err) {
      console.log(stderr);
    }
  });
}

module.exports = launch;

import {exec} from 'child_process';
import {isAbsolute} from 'path';

function launch(path, options = {}) {
  if(!isAbsolute(path)) {
    throw new Error('Application path "%s" is not absolute.', path);
  }
  if(!options instanceof Object) {
    throw new Error('Option passed to launch must be an instance of Object, got ', typeof options);
  }

  if(!options.detached instanceof Boolean) {
    throw new Error('Option key \'detached\' must an instance of Boolean, got ', typeof options.detached);
  }

  return exec(path, {detached: options.detached || true}, (err, stdout, stderr) => {
    if(err) {
      console.log(stderr);
    }
  });
}

module.exports = launch;

Fix throw error instead of returning


/**
 * Created by erdi on 20/10/2016.
 */
$(function () {
    var defaultErrMsg = '请求失败,请稍后重试,或联系管理员!';
    $('#form').submit(function () {
        var form = $(this);
        showLoading();
        form.ajaxSubmit({
            dataType: 'json',
            success: function (result) {
                if (result) {
                    alert(result.msg);
                }
                else {
                    alert(defaultErrMsg);
                }
                hideLoading();
            },
            error: function (jqXHR, errorType, errorDesc) {
                var errMsg = errorDesc ? ('[' + errorDesc + '] ') : '';
                alert(errMsg + defaultErrMsg);
                hideLoading();
            }
        });
        return false;
    });
});

/**
 * Created by erdi on 20/10/2016.
 */
$(function () {
    var defaultErrMsg = '请求失败,请稍后重试,或联系管理员!';
    $('#form').submit(function () {
        var form = $(this);
        showLoading();
        form.ajaxSubmit({
            dataType: 'json',
            success: function (result) {
                if (result) {
                    alert(result.msg);
                    if (result.ok) {
                        $('#form [name=name]').val('');
                    }
                }
                else {
                    alert(defaultErrMsg);
                }
                hideLoading();
            },
            error: function (jqXHR, errorType, errorDesc) {
                var errMsg = errorDesc ? ('[' + errorDesc + '] ') : '';
                alert(errMsg + defaultErrMsg);
                hideLoading();
            }
        });
        return false;
    });
});

Clear class room name if created ok


/*
** Module dependencies
*/
var datasets = require('../controllers/datasets');

module.exports = function(app) {

    // Params
    app.param('datasetId', datasets.dataset);

    // Routes
    app.route('/datasets/:datasetId')
        .get(datasets.show);

    app.route('/datasets/:datasetId/resources/:resourceId/json')
        .get(function (req, res) {
            res.redirect('/datasets/' + req.params.datasetId + '/resources/' + req.params.resourceId + '/download?format=GeoJSON&projection=WGS84');
        });

    app.route('/datasets/:datasetId/resources/:resourceId/download')
        .get(datasets.downloadRelatedResource);

    app.route('/datasets/by-identifier/:identifier')
        .get(datasets.findByIdentifier);

    app.route('/datasets/:datasetId/force-reprocess')
        .post(datasets.forceReprocess);

};

/*
** Module dependencies
*/
var datasets = require('../controllers/datasets');

module.exports = function(app) {

    // Params
    app.param('datasetId', datasets.dataset);

    // Routes
    app.route('/datasets/:datasetId')
        .get(datasets.show);

    app.route('/datasets/:datasetId/resources/:resourceId/json')
        .get(function (req, res) {
            res.redirect('/api/datasets/' + req.params.datasetId + '/resources/' + req.params.resourceId + '/download?format=GeoJSON&projection=WGS84');
        });

    app.route('/datasets/:datasetId/resources/:resourceId/download')
        .get(datasets.downloadRelatedResource);

    app.route('/datasets/by-identifier/:identifier')
        .get(datasets.findByIdentifier);

    app.route('/datasets/:datasetId/force-reprocess')
        .post(datasets.forceReprocess);

};

Fix redirection url for GeoJSON


window.happo = window.happo || {};

window.happo.initChunk = () => {};
window.happo.nextExample = () => {
  if (!window.happoProcessor.next()) {
    return;
  }
  return window.happoProcessor.processCurrent();
};

window.happo = window.happo || {};

window.happo.initChunk = () => {};
window.happo.nextExample = () => {
  if (!window.happoProcessor.next()) {
    return Promise.resolve(undefined);
  }
  return window.happoProcessor.processCurrent();
};

Make sure happo.nextExample always returns a promise


angular.module('events.events.filter', [])
  .filter('showEvents', function () {
    return function (events, filter) {
      var result = [];

      function filterIsSet () {
        return typeof filter !== 'undefined' && (typeof filter.topics !== 'undefined' || typeof filter.searchText !== 'undefined');
      }

      function topicsFilterIsSet () {
        return typeof filter.topics !== 'undefined' && filter.topics.length > 0 && filter.topics instanceof Array;
      }

      function withinTopicsFilter (topics) {
        var ts = topics.map(function (topic) {
          return topic.term_slug;
        });

        for (var i = 0, l = ts.length; i < l; i++){
          if (filter.topics.indexOf(ts[i]) > -1) {
            return true;
          }
        }

        return false;
      }

      function filterByTopics () {
        events.map(function (event) {
          if (!withinTopicsFilter(event.topics)) {
            event.hide = true;
          }
          else {
            event.hide = false;
          }
        });
      }

      function showAll () {
        events.map(function (event) {
          event.hide = false;
        });
      }

      function filterEvents () {
        if (filterIsSet() && topicsFilterIsSet()){
          console.log( 'filter' );
          filterByTopics();
        } else {
          console.log('show all');
          showAll();
        }
        return events;
      }

      return filterEvents();
    };
  });

angular.module('events.events.filter', [])
  .filter('showEvents', function () {
    return function (events, filter) {
      var result = [];

      function filterIsSet () {
        return typeof filter !== 'undefined' && (typeof filter.topics !== 'undefined' || typeof filter.searchText !== 'undefined');
      }

      function topicsFilterIsSet () {
        return typeof filter.topics !== 'undefined' && filter.topics.length > 0 && filter.topics instanceof Array;
      }

      function withinTopicsFilter (topics) {
        var ts = topics.map(function (topic) {
          return topic.term_slug;
        });

        for (var i = 0, l = ts.length; i < l; i++){
          if (filter.topics.indexOf(ts[i]) > -1) {
            return true;
          }
        }

        return false;
      }

      function filterByTopics () {
        events.map(function (event) {
          if (!withinTopicsFilter(event.topics)) {
            event.hide = true;
          }
          else {
            event.hide = false;
          }
        });
      }

      function showAll () {
        events.map(function (event) {
          event.hide = false;
        });
      }

      function filterEvents () {
        if (filterIsSet() && topicsFilterIsSet()){
          filterByTopics();
        } else {
          showAll();
        }
        return events;
      }

      return filterEvents();
    };
  });

Remove console logs from files...


import invariant from 'invariant';

import PathStrategy from '../path';
import NativeStrategy from './nativeStrategy';
import FetchStrategy from './fetchStrategy';

const directionStrategy = ({ props, type: { defaultProps } }, parentProps) => {
  const {
    baseURL,
    requestStrategy,
    origin,
    destination,
    apiKey,
    waypoints,
    avoid,
    mode,
    transitMode,
    transitRoutingPreference,

    weight,
    color,
    fillcolor,
    geodesic,

    ...rest
  } = props;

  invariant(origin, 'Origin prop is required');
  invariant(destination, 'Destination prop is required');

  // Use the parent's API key if one isn't set here.
  const key = apiKey ? apiKey : parentProps.apiKey;

  const data = {
    key,
    baseURL,
    origin,
    destination,
    waypoints,
    avoid,
    mode,
    transitMode,
    transitRoutingPreference,
    ...rest,
  };

  let pathPromise;

  if (typeof requestStrategy !== 'string') {
    pathPromise = requestStrategy(data);
  } else {
    switch (requestStrategy) {
      case 'native':
        pathPromise = NativeStrategy(data);
        break;
      case 'fetch':
        pathPromise = FetchStrategy(data);
        break;
      default:
        throw new Error('Specify a Request strategy to get directions from');
    }
  }

  return pathPromise.then(path =>
    PathStrategy({
      props: { weight, color, fillcolor, geodesic, points: `enc:${path}` },
      type: { defaultProps },
    })
  );
};

export default directionStrategy;

import invariant from 'invariant';

import PathStrategy from '../path';
import NativeStrategy from './nativeStrategy';
import FetchStrategy from './fetchStrategy';

const directionStrategy = ({ props, type: { defaultProps } }, parentProps) => {
  const {
    baseURL,
    requestStrategy,
    origin,
    destination,
    apiKey,
    waypoints,
    avoid,
    mode,
    transitMode,
    transitRoutingPreference,

    weight,
    color,
    fillcolor,
    geodesic,

    ...rest
  } = props;

  invariant(origin, 'Origin prop is required');
  invariant(destination, 'Destination prop is required');

  // Use the parent's API key if one isn't set here.
  const key = apiKey ? apiKey : parentProps ? parentProps.apiKey : '';

  const data = {
    key,
    baseURL,
    origin,
    destination,
    waypoints,
    avoid,
    mode,
    transitMode,
    transitRoutingPreference,
    ...rest,
  };

  let pathPromise;

  if (typeof requestStrategy !== 'string') {
    pathPromise = requestStrategy(data);
  } else {
    switch (requestStrategy) {
      case 'native':
        pathPromise = NativeStrategy(data);
        break;
      case 'fetch':
        pathPromise = FetchStrategy(data);
        break;
      default:
        throw new Error('Specify a Request strategy to get directions from');
    }
  }

  return pathPromise.then(path =>
    PathStrategy({
      props: { weight, color, fillcolor, geodesic, points: `enc:${path}` },
      type: { defaultProps },
    })
  );
};

export default directionStrategy;

Read ApiKey from parent only if it is set


var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
  host: process.env.ELASTICSEARCH,
});

function query(q) {
  return client.search({
           index: 'chadocs',
           type: 'document',
           body: {
             query: {
               filtered: {
                 query: {
                   query_string: {
                     query: q
                   }
                 }
               }
             },
             highlight: {
               fields: {
                 content: {}
               }
             },
             fields: [
               "title",
               "original_source_url"
             ],
             from: 0,
             size: 50,
             sort: {
               _score: {
                 order: "desc"
               }
             },
           }

         });
}

exports.query = query;

var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
  host: process.env.ELASTICSEARCH,
});

function query(q) {
  return client.search({
           index: 'chadocs',
           type: 'document',
           body: {
             query: {
               filtered: {
                 query: {
                   match: {
                     content: q
                   }
                 }
               }
             },
             highlight: {
               fields: {
                 content: {}
               }
             },
             fields: [
               "title",
               "original_source_url"
             ],
             from: 0,
             size: 50,
             sort: {
               _score: {
                 order: "desc"
               }
             },
           }

         });
}

exports.query = query;

Use match instead of query string for now.


// server startup
Meteor.startup(function() {

  /* server startup */

  // add environment variables from settings file to current process environment
  if (Settings.env)
    _.extend(process.env, Settings.env);

  // print uptime to console
  uptimeLogging();

  // run every 6 hours
  Meteor.setInterval(runAfter6hours, 1000 * 60 * 60 * 6);

});

// run this function every 6 hours
var runAfter6hours = function() {

  // update user profile picture on startup
  ServicesConfiguration.updateProfilePictures();
}

// show server uptime in console
var uptimeLogging = function() {
  var startupDate = new Date();
  var logging = function() {
    log("[Server Uptime]: " + moment(startupDate).fromNow(true));
  }
  Meteor.setInterval(logging, 15 * 60 * 1000);
}

// server startup
Meteor.startup(function() {

  /* server startup */

  // add environment variables from settings file to current process environment
  if (Settings.env)
    _.extend(process.env, Settings.env);

  // print uptime to console
  uptimeLogging();

  // run after 15 minutes after startup
  // taken into account that the Heroku server
  // is restarted once every day
  Meteor.setTimeout(runAfterStartupDelayed, 1000 * 60 * 15);

});

// run after 15 minutes after startup
// taken into account that the Heroku server
// is restarted once every day.
// And preventing development machines
// from running too often.
var runAfterStartupDelayed = function() {

  // update user profile picture on startup
  ServicesConfiguration.updateProfilePictures();
}

// show server uptime in console
var uptimeLogging = function() {
  var startupDate = new Date();
  var logging = function() {
    log("[Server Uptime]: " + moment(startupDate).fromNow(true));
  }
  Meteor.setInterval(logging, 15 * 60 * 1000);
}

Update profile picture 15 minutes after startup


/**
 * @license
 * Copyright 2016 Google Inc. 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.
 */

foam.CLASS({
  package: 'foam.u2.stack',
  name: 'StackView',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.stack.Stack'
  ],

  exports: [ 'data as stack' ],

  properties: [
    {
      name: 'data',
      factory: function() { return this.Stack.create(); }
    },
    {
      class: 'Boolean',
      name: 'showActions',
      value: true
    }
  ],

  methods: [
    function initE() {
      this.setNodeName('div');

      if ( this.showActions )
        this.add(this.Stack.BACK, this.Stack.FORWARD);

      this.add(this.slot(function(s) {
        return foam.u2.ViewSpec.createView(s, null, this, this.__subSubContext__);
      }, this.data$.dot('top')));
    }
  ]
});

/**
 * @license
 * Copyright 2016 Google Inc. 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.
 */

foam.CLASS({
  package: 'foam.u2.stack',
  name: 'StackView',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.stack.Stack'
  ],

  exports: [ 'data as stack' ],

  properties: [
    {
      name: 'data',
      factory: function() { return this.Stack.create(); }
    },
    {
      class: 'Boolean',
      name: 'showActions',
      value: true
    }
  ],

  methods: [
    // TODO: Why is this init() instead of initE()? Investigate and maybe fix.
    function init() {
      this.setNodeName('div');

      if ( this.showActions )
        this.add(this.Stack.BACK, this.Stack.FORWARD);

      this.add(this.slot(function(s) {
        return foam.u2.ViewSpec.createView(s, null, this, this.__subSubContext__);
      }, this.data$.dot('top')));
    }
  ]
});

Revert initE back to init, since change was breaking lots of things.


'use strict';

var mime = require('mime');
var mix = require('mix');
var path = require('path');
var vfs = require('vinyl-fs');

module.exports = function (options) {
    var base = path.resolve(options.base);

    var globs;
    if (typeof options.globs === 'string') {
        globs = [options.globs];
    } else {
        globs = options.globs;
    }
    globs = globs.map(function (g) { return path.join(base, g) });

    function nodeFromVinyl(file) {
        return {
            name: path.relative(base, file.path),
            base: base,
            data: file.contents,
            stat: file.stat,
            metadata: {
                mime: mime.lookup(file.path)
            },
            siblings: []
        };
    }

    return new mix.Stream(function (sink) {
        var watcher = new mix.Watcher();
        watcher.on('change', pushNext);

        pushNext();

        function pushNext() {
            readTree(sink.push);
        }

        function readTree(callback) {
            var stream = vfs.src(globs, {
                base: base
            });
            var files = [];
            stream.on('data', function (file) {
                if (!file.isNull()) {
                    watcher.add(file.path);
                    files.push(file);
                }
            });
            stream.on('end', function () {
                callback(new mix.Tree(files.map(nodeFromVinyl)));
            }.bind(this));
        }

        return function dispose() {
            watcher.dispose();
        };
    });
};

'use strict';

var mime = require('mime');
var mix = require('mix');
var path = require('path');
var vfs = require('vinyl-fs');

module.exports = function (options) {
    var base = path.resolve(options.base);

    var globs;
    if (typeof options.globs === 'string') {
        globs = [options.globs];
    } else {
        globs = options.globs;
    }

    function nodeFromVinyl(file) {
        return {
            name: path.relative(base, file.path),
            base: base,
            data: file.contents,
            stat: file.stat,
            metadata: {
                mime: mime.lookup(file.path)
            },
            siblings: []
        };
    }

    return new mix.Stream(function (sink) {
        var watcher = new mix.Watcher();
        watcher.on('change', pushNext);

        pushNext();

        function pushNext() {
            readTree(sink.push);
        }

        function readTree(callback) {
            var stream = vfs.src(globs, {
                cwd: base
            });
            var files = [];
            stream.on('data', function (file) {
                if (!file.isNull()) {
                    watcher.add(file.path);
                    files.push(file);
                }
            });
            stream.on('end', function () {
                callback(new mix.Tree(files.map(nodeFromVinyl)));
            }.bind(this));
        }

        return function dispose() {
            watcher.dispose();
        };
    });
};

Fix globbing issue in mix/files


/**
 * Main controller for the Huna JS app. Shows the main (index) page
 */
app.controller('ErrorController', function($scope, $interval){

  var stop;
  $scope.timeout = "";
  $scope.busy = false;

  $scope.parseError = function(){
    countDown();
    var a = "";
    a.asdf = asdf;
  };

  $scope.syntaxError = function(){
    countDown();
    eval("var a = b;");
  };

  $scope.uncaughtException = function(){
    countDown();
    throw new Error("Uncaught Exception...");
  };

  $scope.stop = function(){
    if (angular.isDefined(stop)){
      $interval.cancel(stop);
      stop = undefined;
      $scope.timeout = "";
      $scope.busy = false;
    }
  };

  function countDown(){
    $scope.busy = true;
    $scope.timeout = 8;
    stop = $interval(function(){
      $scope.timeout--;
      if ($scope.timeout <= 0){
        $scope.stop();
      }
    }, 1000);
  }

  $scope.$on('$destroy', function() {
    $scope.stop();
  });

});

/**
 * Main controller for the Huna JS app. Shows the main (index) page
 */
app.controller('ErrorController', function($scope, $interval){

  var stop;
  $scope.timeout = "";
  $scope.busy = false;

  $scope.parseError = function(){
    countDown();
    var a = "";
    a.asdf = asdf;
  };

  $scope.syntaxError = function(){
    countDown();
    eval("var a = b;"); // jshint ignore:line
  };

  $scope.uncaughtException = function(){
    countDown();
    throw new Error("Uncaught Exception...");
  };

  $scope.stop = function(){
    if (angular.isDefined(stop)){
      $interval.cancel(stop);
      stop = undefined;
      $scope.timeout = "";
      $scope.busy = false;
    }
  };

  function countDown(){
    $scope.busy = true;
    $scope.timeout = 8;
    stop = $interval(function(){
      $scope.timeout--;
      if ($scope.timeout <= 0){
        $scope.stop();
      }
    }, 1000);
  }

  $scope.$on('$destroy', function() {
    $scope.stop();
  });

});

Fix evil eval warning in lint


import React, { PureComponent } from 'react';
import Modal from 'react-modal';

class CreateTicketModal extends PureComponent {
  render() {
    return (
      <Modal
        contentLabel="Create Ticket Modal"
        isOpen={this.props.expanded}
        onRequestClose={this.props.toggleCreateTicketForm}
        overlayClassName="modal-overlay ticket-modal"
        shouldCloseOnOverlayClick={true}
      >
        {this.props.children}
      </Modal>
    )
  }
}

export default CreateTicketModal;

import React, { PureComponent } from 'react';
import Modal from 'react-modal';
import { connect } from 'react-redux';

class CreateTicketModal extends PureComponent {
  render() {
    return (
      <Modal
        contentLabel="Create Ticket Modal"
        isOpen={this.props.expanded}
        onRequestClose={this.props.toggleCreateTicketForm}
        overlayClassName={`modal-overlay ticket-modal ${this.props.theme}-modal`}
        shouldCloseOnOverlayClick={true}
      >
        {this.props.children}
      </Modal>
    )
  }
}

const mapStateToProps = state => ({
  theme: state.app.theme
});

export default connect(mapStateToProps)(CreateTicketModal);

Add dark mode to the create ticket modal


import React from "react";
import PropTypes from "prop-types";
import Character from "./Character";

const CharacterString = props => {
  const text = `${props.children}`;
  const chars = text.split("");
  return (
    <div {...props}>
      {chars.map((character, index) => (
        <Character key={index + character}>{character}</Character>
      ))};
    </div>
  );
};

CharacterString.propsTypes = {
  children: PropTypes.string
};

export default CharacterString;

import React from "react";
import PropTypes from "prop-types";
import Character from "./Character";

const CharacterString = props => {
  const text = `${props.children}` || "";
  const chars = text.split("");
  return (
    <div {...props}>
      {chars.map((character, index) => (
        <Character key={index + character}>{character}</Character>
      ))};
    </div>
  );
};

CharacterString.propsTypes = {
  children: PropTypes.string
};

export default CharacterString;

Use empty string for falsy character strings


/*
 * Copyright 2017 Hewlett Packard Enterprise Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

define([
    'underscore',
    './widget',
    'text!find/idol/templates/page/dashboards/widgets/current-time-widget.html',
    'moment-timezone-with-data'
], function(_, Widget, template, moment) {
    'use strict';

    return Widget.extend({
        currentTimeTemplate: _.template(template),

        initialize: function(options) {
            Widget.prototype.initialize.apply(this, arguments);

            this.dateFormat = this.widgetSettings.dateFormat || 'll';
            this.timeFormat = this.widgetSettings.timeFormat || 'HH:mm z';
            this.timeZone = this.widgetSettings.timeZone || moment.tz.guess();
        },

        render: function() {
            Widget.prototype.render.apply(this);

            this.$content.html(this.currentTimeTemplate());

            this.$time = this.$('.current-time');
            this.$day = this.$('.day');
            this.$date = this.$('.date');

            this.updateTime();

            setInterval(this.updateTime.bind(this), 1000);
        },

        updateTime: function() {
            const time = moment().tz(this.timeZone);

            this.$time.text(time.format(this.timeFormat));
            this.$day.text(time.format('dddd'));
            this.$date.text(time.format(this.dateFormat));
        }
    });
});

/*
 * Copyright 2017 Hewlett Packard Enterprise Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

define([
    'underscore',
    './widget',
    'text!find/idol/templates/page/dashboards/widgets/current-time-widget.html',
    'moment-timezone-with-data'
], function(_, Widget, template, moment) {
    'use strict';

    return Widget.extend({
        currentTimeTemplate: _.template(template),

        initialize: function(options) {
            Widget.prototype.initialize.apply(this, arguments);

            this.dateFormat = this.widgetSettings.dateFormat || 'll';
            this.timeFormat = this.widgetSettings.timeFormat || 'HH:mm z';
            this.timeZone = this.widgetSettings.timeZone || moment.tz.guess();
        },

        render: function() {
            Widget.prototype.render.apply(this);

            this.$content.html(this.currentTimeTemplate());

            this.$time = this.$('.current-time');
            this.$day = this.$('.day');
            this.$date = this.$('.date');

            this.updateTime();

            setInterval(this.updateTime.bind(this), 250);
        },

        updateTime: function() {
            const time = moment().tz(this.timeZone);

            this.$time.text(time.format(this.timeFormat));
            this.$day.text(time.format('dddd'));
            this.$date.text(time.format(this.dateFormat));
        }
    });
});

Increase current time widget update freq. to 4 Hz


// App config the for development environment.
// Do not require this directly. Use ./src/config instead.

const HOST = process.env.HOST || "localhost",
  apiBaseUrl = process.env.API_URL || `http://${HOST}:2000`,
  gitHubProject = "openfisca/openfisca-france",
  gitWebpageUrl = "https://github.com/openfisca/legislation-explorer",
  piwikConfig = null,
  useCommitReferenceFromApi = true,
  websiteUrl = `http://${HOST}:2010/`

export default {
  apiBaseUrl,
  gitHubProject,
  gitWebpageUrl,
  piwikConfig,
  useCommitReferenceFromApi,
  websiteUrl
}

// App config the for development environment.
// Do not require this directly. Use ./src/config instead.

const HOST = process.env.HOST || "localhost",
  apiBaseUrl = process.env.API_URL || `http://${HOST}:2000`,
  gitHubProject = "openfisca/openfisca-france",
  gitWebpageUrl = "https://github.com/openfisca/legislation-explorer",
  piwikConfig = null,
  useCommitReferenceFromApi = true,
  websiteUrl = "https://www.openfisca.fr/"

export default {
  apiBaseUrl,
  gitHubProject,
  gitWebpageUrl,
  piwikConfig,
  useCommitReferenceFromApi,
  websiteUrl
}

Use prod website URL in dev env


import D3MultiClick from './D3MultiClick';
import FieldProvider from './FieldProvider';
import Histogram2DProvider from './Histogram2DProvider';
import LegendProvider from './LegendProvider';
import ScoresProvider from './ScoresProvider';
import SelectionProvider from './SelectionProvider';

export default {
  D3MultiClick,
  FieldProvider,
  Histogram2DProvider,
  LegendProvider,
  ScoresProvider,
  SelectionProvider,
};

import D3MultiClick from './D3MultiClick';
import FieldProvider from './FieldProvider';
import Histogram1DProvider from './Histogram1DProvider';
import Histogram2DProvider from './Histogram2DProvider';
import HistogramBinHoverProvider from './HistogramBinHoverProvider';
import LegendProvider from './LegendProvider';
import MutualInformationProvider from './MutualInformationProvider';
import PartitionProvider from './PartitionProvider';
import ScoresProvider from './ScoresProvider';
import SelectionProvider from './SelectionProvider';

export default {
  D3MultiClick,
  FieldProvider,
  Histogram1DProvider,
  Histogram2DProvider,
  HistogramBinHoverProvider,
  LegendProvider,
  MutualInformationProvider,
  PartitionProvider,
  ScoresProvider,
  SelectionProvider,
};

Add missing entry in Core module


import * as Pluggable from "../../pluggable";
import resolve from "../../resolve";

const createModule = Pluggable.sync(function createModule (overrides) {
  return Object.assign({
    path: null,
    ns: null,
    nsPath: null,
    nsRoot: null,
    rawSource: null,
    ast: null,
    requireNodes: null,
    dependencies: null,
    hash: null
  }, overrides);
});

const preresolve = Pluggable.sync(function preresolve (requireStr) {
  return requireStr;
});

function resolveModule (requireStr, contextPath, ns, nsRoot) {
  contextPath = contextPath || this.opts.root;

  requireStr = this.preresolve(requireStr, contextPath);

  const resolved = resolve(
    requireStr,
    contextPath || this.opts.root,
    ns || this.opts.ns,
    nsRoot || this.opts.root,
    this.opts.extensions
  );

  if (!resolved) {
    throw new Error("Cannot resolve '" + requireStr + "' from '" + contextPath + "'.");
  }

  return this.createModule(resolved);
}

export default Pluggable.sync(resolveModule, { preresolve, createModule });

import * as Pluggable from "../../pluggable";
import resolve from "../../resolve";

const createModule = Pluggable.sync(function createModule (overrides) {
  return Object.assign({
    path: null,
    ns: null,
    nsPath: null,
    nsRoot: null,
    rawSource: null,
    ast: null,
    requireNodes: null,
    dependencies: null,
    hash: null
  }, overrides);
});

const preresolve = Pluggable.sync(function preresolve (requireStr) {
  return requireStr;
});

function resolveModule (requireStr, contextPath, ns, nsRoot) {
  contextPath = contextPath || this.opts.root;

  requireStr = this.preresolve(requireStr, contextPath);

  const resolved = resolve(
    requireStr,
    contextPath || this.opts.root,
    ns || this.opts.ns,
    nsRoot || this.opts.root,
    this.opts.extensions
  );

  if (!resolved) {
    throw new Error(`Cannot resolve ${requireStr} from ${contextPath}.`);
  }

  return this.createModule(resolved);
}

export default Pluggable.sync(resolveModule, { preresolve, createModule });

Convert string concat to template string


import packageJson from 'package-json';

export const getLatestVersion = (req, res) => {
    packageJson('cncjs', 'latest')
        .then(json => {
            const {
                name,
                version,
                description,
                homepage
            } = { ...json };

            res.send({ name, version, description, homepage });
        })
        .catch((err) => {
            res.status(400).send({
                err: err
            });
        });
};

import packageJson from 'package-json';

export const getLatestVersion = (req, res) => {
    packageJson('cncjs')
        .then(data => {
            const latest = data['dist-tags'].latest;
            const time = data.time[latest];
            const {
                name,
                version,
                description,
                homepage
            } = { ...data.versions[latest] };

            res.send({ time, name, version, description, homepage });
        })
        .catch(err => {
            res.status(400).send({
                err: err
            });
        });
};

Return update time for the latest release


'use strict';

angular.module('<%=angularAppName%>')
    .factory('errorHandlerInterceptor', function ($q, $rootScope) {
        return {
            'responseError': function (response) {
                if (!(response.status === 401 && response.data.path.indexOf('/api/account') === 0 )){
	                $rootScope.$emit('<%=angularAppName%>.httpError', response);
	            }
                return $q.reject(response);
            }
        };
    });

'use strict';

angular.module('<%=angularAppName%>')
    .factory('errorHandlerInterceptor', function ($q, $rootScope) {
        return {
            'responseError': function (response) {
                if (!(response.status === 401 && (response.data === '' || response.data.path.indexOf('/api/account') === 0 ))) {
                    $rootScope.$emit('<%=angularAppName%>.httpError', response);
                }
                return $q.reject(response);
            }
        };
    });

Check when no data is returned, which is the case with JWT expired token


var lodash = require('lodash');
var expect = require('chai').expect;
var testPath = require('path').join(__dirname, '../../src/colors/randomColor');
var _ = require(testPath)(lodash);

module.exports = function() {
    describe('randomColor', function() {
        it('exists', function() {
            expect(_.randomColor).to.be.a('function');
        });

        it('generates a color', function() {
            var color = _.randomColor();
            expect(color.r).to.be.a('number');
            expect(color.g).to.be.a('number');
            expect(color.b).to.be.a('number');

            expect(color.r).to.be.below(256);
            expect(color.g).to.be.below(256);
            expect(color.b).to.be.below(256);

            expect(color.r).to.be.above(0);
            expect(color.g).to.be.above(0);
            expect(color.b).to.be.above(0);
        });
    });
};

var lodash = require('lodash');
var expect = require('chai').expect;
var testPath = require('path').join(__dirname, '../../src/colors/randomColor');
var _ = require(testPath)(lodash);

module.exports = function() {
    describe('randomColor', function() {
        it('exists', function() {
            expect(_.randomColor).to.be.a('function');
        });

        it('generates a color', function() {
            var color = _.randomColor();
            expect(color.r).to.be.a('number');
            expect(color.g).to.be.a('number');
            expect(color.b).to.be.a('number');

            expect(color.r).to.be.below(256);
            expect(color.g).to.be.below(256);
            expect(color.b).to.be.below(256);

            expect(color.r).to.be.above(-1);
            expect(color.g).to.be.above(-1);
            expect(color.b).to.be.above(-1);
        });
    });
};

Fix range error in randomColor test


"use strict";

var debug = require('debug')('server');
var express = require('express');

var routes = require('./routes/index');

var app = express();

app.use('/', routes);

app.set('view engine', 'jade');

var server = app.listen(process.env.PORT || 3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  debug('listening at http://%s:%s', host, port);
});

"use strict";

var debug = require('debug')('server');
var express = require('express');
var path = require('path');

var routes = require('./routes/index');

var app = express();

app.use('/', routes);

app.set('view engine', 'jade');
app.set('views', path.join(__dirname, 'views'));

var server = app.listen(process.env.PORT || 3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  debug('listening at http://%s:%s', host, port);
});

Change views directory to a relative path.


(function($){
$.fn.blogfeed = function(options) {
    var defaults = {
        postcount: 5
    };
    var options = $.extend(defaults, options);

    return this.each(function() {
        var $obj = $(this);
        $.getFeed({url: options.feedurl, success: function(feed) {
            var k = 0;
            var out = '';
            $.each(feed.items, function(i, item) {
                if(++k > options.postcount) { return; }
                var time = new Date(Date.parse(item.updated));
                var timestamp = ''
                    +time.getDate()+'.'
                    +time.getMonth()+'.'
                    +time.getFullYear()+' '
                    +(time.getHours() < 10 ? '0'+time.getHours() : time.getHours())+':'
                    +(time.getMinutes() < 10 ? '0'+time.getMinutes() : time.getMinutes());
                out += '
'+item.title+'
';
                out += '
'+item.description+'
';
                out += 'Posted on '+timestamp+'';
            });
            $obj.html(out);
			fixBlogImageContainer();
        }});
    });
};

function fixBlogImageContainer()
{
	$('.tr-caption-container').each(function(){
		var width = $( this ).find('img').width();
		$( this ).width( width );
	});
}

})(jQuery);

(function($){
$.fn.blogfeed = function(options) {
    var defaults = {
        postcount: 5
    };
    var options = $.extend(defaults, options);

    return this.each(function() {
        var $obj = $(this);
        $.getFeed({url: options.feedurl, success: function(feed) {
            var k = 0;
            var out = '';
            $.each(feed.items, function(i, item) {
                if(++k > options.postcount) { return; }
                var time = new Date(Date.parse(item.updated));
                var timestamp = ''
                    +time.getDate()+'.'
                    +(time.getMonth()+1)+'.'
                    +time.getFullYear()+' '
                    +(time.getHours() < 10 ? '0'+time.getHours() : time.getHours())+':'
                    +(time.getMinutes() < 10 ? '0'+time.getMinutes() : time.getMinutes());
                out += '
'+item.title+'
';
                out += '
'+item.description+'
';
                out += 'Posted on '+timestamp+'';
            });
            $obj.html(out);
			fixBlogImageContainer();
        }});
    });
};

function fixBlogImageContainer()
{
	$('.tr-caption-container').each(function(){
		var width = $( this ).find('img').width();
		$( this ).width( width );
	});
}

})(jQuery);

Fix timestamp on rss feeds