import React from 'react';

const withCountry = component =>
	class extends React.Component {
		static displayName = `withCountry(${component.displayName
			|| component.name})`;

		constructor(props) {
			super(props);

			this.state = {
				country: 'US',
			};
		}

		async componentDidMount() {
			try {
				const response = await fetch('//freegeoip.net/json/');
				const data = await response.json();

				this.setState({country: data.country_code});
			}
			catch (err) {
				// Failed to fetch can happen if the user has a blocker (ad, tracker...)
				trackJs.track(`Error when getting the country: ${err.message}`);
			}
		}

		render() {
			const {country} = this.state;

			return React.createElement(component, {
				...this.props,
				country,
			});
		}
	};

export default withCountry;

import React from 'react';

const withCountry = component =>
	class extends React.Component {
		static displayName = `withCountry(${component.displayName
			|| component.name})`;

		constructor(props) {
			super(props);

			this.state = {
				country: 'US',
			};
		}

		async componentDidMount() {
			try {
				const response = await fetch('//ipinfo.io/json');
				const data = await response.json();

				this.setState({country: data.country});
			}
			catch (err) {
				// Failed to fetch can happen if the user has a blocker (ad, tracker...)
				window.trackJs.track(`Error when getting the country: ${err.message}`);

				// trying another server just to be sure
				try {
					const response = await fetch('//get.geojs.io/v1/ip/country.json');
					const data = await response.json();

					this.setState({country: data.country});
				}
				catch (err2) {
					// giving up
					window.trackJs.track(
						`Error when getting the country: ${err2.message}`,
					);
				}
			}
		}

		render() {
			const {country} = this.state;

			return React.createElement(component, {
				...this.props,
				country,
			});
		}
	};

export default withCountry;

Change endpoint for 2 other free services


class Element {
  mount(el) {
    if (typeof el === "string") {
      el = document.querySelector(el);
    }

    el.innerHTML = `
      <input id="stripe-cardnumber" name="cardnumber" placeholder="Card number" size="16" type="text">
      <input name="exp-date" placeholder="MM / YY" size="6" type="text">
      <input name="cvc" placeholder="CVC" size="3" type="text">
    `;
  }

  addEventListener(event) {
    return true;
  }
}

window.Stripe = () => {
  const fetchLastFour = () => {
    return document.getElementById("stripe-cardnumber").value.substr(-4, 4);
  };

  return {
    elements: () => {
      return {
        create: (type, options) => new Element()
      };
    },

    createToken: card => {
      return new Promise(resolve => {
        resolve({ token: { id: "tok_123", card: { last4: fetchLastFour() } } });
      });
    }
  };
};

class Element {
  mount(el) {
    if (typeof el === "string") {
      el = document.querySelector(el);
    }

    el.innerHTML = `
      <input id="stripe-cardnumber" name="cardnumber" placeholder="Card number" size="16" type="text">
      <input name="exp-date" placeholder="MM / YY" size="6" type="text">
      <input name="cvc" placeholder="CVC" size="3" type="text">
    `;
  }

  addEventListener(event) {
    return true;
  }
}

window.Stripe = () => {
  const fetchLastFour = () => {
    return document.getElementById("stripe-cardnumber").value.substr(-4, 4);
  };

  return {
    createPaymentMethod: () => {
      return new Promise(resolve => {
        resolve({
          paymentMethod: {
            id: "pm_123",
            card: {
              brand: 'visa',
              last4: fetchLastFour(),
              exp_month: "10",
              exp_year: "2050"
            }
          }
        });
      });
    },

    elements: () => {
      return {
        create: (type, options) => new Element()
      };
    },

    createToken: card => {
      return new Promise(resolve => {
        resolve({ token: { id: "tok_123", card: { last4: fetchLastFour() } } });
      });
    }
  };
};

Add another missing method to StripeJS mock


/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

import Platform from '../../Utilities/Platform';
import typeof AnimatedFlatList from './components/AnimatedFlatList';
import typeof AnimatedImage from './components/AnimatedImage';
import typeof AnimatedScrollView from './components/AnimatedScrollView';
import typeof AnimatedSectionList from './components/AnimatedSectionList';
import typeof AnimatedText from './components/AnimatedText';
import typeof AnimatedView from './components/AnimatedView';

const AnimatedMock = require('./AnimatedMock');
const AnimatedImplementation = require('./AnimatedImplementation');

const Animated = ((Platform.isTesting
  ? AnimatedMock
  : AnimatedImplementation): typeof AnimatedMock);

module.exports = {
  get FlatList(): AnimatedFlatList {
    return require('./components/AnimatedFlatList');
  },
  get Image(): AnimatedImage {
    return require('./components/AnimatedImage');
  },
  get ScrollView(): AnimatedScrollView {
    return require('./components/AnimatedScrollView');
  },
  get SectionList(): AnimatedSectionList {
    return require('./components/AnimatedSectionList');
  },
  get Text(): AnimatedText {
    return require('./components/AnimatedText');
  },
  get View(): AnimatedView {
    return require('./components/AnimatedView');
  },
  ...Animated,
};

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

import Platform from '../../Utilities/Platform';
import typeof AnimatedFlatList from './components/AnimatedFlatList';
import typeof AnimatedImage from './components/AnimatedImage';
import typeof AnimatedScrollView from './components/AnimatedScrollView';
import typeof AnimatedSectionList from './components/AnimatedSectionList';
import typeof AnimatedText from './components/AnimatedText';
import typeof AnimatedView from './components/AnimatedView';

const AnimatedMock = require('./AnimatedMock');
const AnimatedImplementation = require('./AnimatedImplementation');

const Animated = ((Platform.isTesting ||
(Platform.OS === 'android' && global.RN$Bridgeless)
  ? AnimatedMock
  : AnimatedImplementation): typeof AnimatedMock);

module.exports = {
  get FlatList(): AnimatedFlatList {
    return require('./components/AnimatedFlatList');
  },
  get Image(): AnimatedImage {
    return require('./components/AnimatedImage');
  },
  get ScrollView(): AnimatedScrollView {
    return require('./components/AnimatedScrollView');
  },
  get SectionList(): AnimatedSectionList {
    return require('./components/AnimatedSectionList');
  },
  get Text(): AnimatedText {
    return require('./components/AnimatedText');
  },
  get View(): AnimatedView {
    return require('./components/AnimatedView');
  },
  ...Animated,
};

Disable animations on Android again


'use strict';

var grunt = require('grunt');

// Check that the version we're exporting is the same one we expect in the
// package. This is not an ideal way to do this, but makes sure that we keep
// them in sync.
var reactVersionExp = /\bReact\.version\s*=\s*['"]([^'"]+)['"];/;

module.exports = function() {
  var reactVersion = reactVersionExp.exec(
    grunt.file.read('./src/browser/React.js')
  )[1];
  var npmReactVersion = grunt.file.readJSON('./npm-react/package.json').version;
  var reactToolsVersion = grunt.config.data.pkg.version;

  if (reactVersion !== reactToolsVersion) {
    grunt.log.error(
      'React version does not match react-tools version. Expected %s, saw %s',
      reactToolsVersion,
      reactVersion
    );
    return false;
  }
  if (npmReactVersion !== reactToolsVersion) {
    grunt.log.error(
      'npm-react version does not match react-tools veersion. Expected %s, saw %s',
      reactToolsVersion,
      npmReactVersion
    );
    return false;
  }
};

'use strict';

var grunt = require('grunt');

// Check that the version we're exporting is the same one we expect in the
// package. This is not an ideal way to do this, but makes sure that we keep
// them in sync.
var reactVersionExp = /\bReact\.version\s*=\s*['"]([^'"]+)['"];/;

module.exports = function() {
  var reactVersion = reactVersionExp.exec(
    grunt.file.read('./src/browser/ui/React.js')
  )[1];
  var npmReactVersion = grunt.file.readJSON('./npm-react/package.json').version;
  var reactToolsVersion = grunt.config.data.pkg.version;

  if (reactVersion !== reactToolsVersion) {
    grunt.log.error(
      'React version does not match react-tools version. Expected %s, saw %s',
      reactToolsVersion,
      reactVersion
    );
    return false;
  }
  if (npmReactVersion !== reactToolsVersion) {
    grunt.log.error(
      'npm-react version does not match react-tools veersion. Expected %s, saw %s',
      reactToolsVersion,
      npmReactVersion
    );
    return false;
  }
};

Fix verion-check to look in right place for React.js


define([
    'backgrid',
    'orodatagrid/js/datagrid/formatter/cell-formatter'
], function(Backgrid, CellFormatter) {
    'use strict';

    var StringCell;

    /**
     * String column cell. Added missing behaviour.
     *
     * @export  oro/datagrid/cell/string-cell
     * @class   oro.datagrid.cell.StringCell
     * @extends Backgrid.StringCell
     */
    StringCell = Backgrid.StringCell.extend({
        /**
         @property {(Backgrid.CellFormatter|Object|string)}
         */
        formatter: new CellFormatter()
    });

    return StringCell;
});

define([
    'backgrid',
    'orodatagrid/js/datagrid/formatter/cell-formatter'
], function(Backgrid, CellFormatter) {
    'use strict';

    var StringCell;

    /**
     * String column cell. Added missing behaviour.
     *
     * @export  oro/datagrid/cell/string-cell
     * @class   oro.datagrid.cell.StringCell
     * @extends Backgrid.StringCell
     */
    StringCell = Backgrid.StringCell.extend({
        /**
         @property {(Backgrid.CellFormatter|Object|string)}
         */
        formatter: new CellFormatter(),

        /**
         * @inheritDoc
         */
        render: function() {
            var render = StringCell.__super__.render.apply(this, arguments);

            this.enterEditMode();

            return render;
        },

        /**
         * @inheritDoc
         */
        enterEditMode: function() {
            if (this.column.get('editable')) {
                StringCell.__super__.enterEditMode.apply(this, arguments);
            }
        },

        /**
         * @inheritDoc
         */
        exitEditMode: function() {
            if (!this.column.get('editable')) {
                StringCell.__super__.exitEditMode.apply(this, arguments);
            }
        }
    });

    return StringCell;
});

Add quantity validation - added support of editable flag for string cell


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

const { service } = Ember.inject;
const { alias } = Ember.computed;

import { task } from 'ember-concurrency';

export default Ember.Component.extend({
  auth: service(),
  flashes: service(),

  user: alias('auth.currentUser'),

  canActivate: Ember.computed('user.pushPermissions.[]', 'repo', function () {
    let user = this.get('user');
    if (user) {
      let permissions = user.get('pushPermissions'),
        repoId = parseInt(this.get('repo.id'));

      return permissions.contains(repoId);
    } else {
      return false;
    }
  }),

  activate: task(function* () {
    const apiEndpoint = config.apiEndpoint;
    const repoId = this.get('repo.id');

    try {
      const response = yield Ember.$.ajax(`${apiEndpoint}/v3/repo/${repoId}/enable`, {
        headers: {
          Authorization: `token ${this.get('auth').token()}`
        },
        method: 'POST'
      });

      if (response.active) {
        this.get('pusher').subscribe(`repo-${repoId}`);

        this.get('repo').set('active', true);
        this.get('flashes').success('Repository has been successfully activated.');
      }
    } catch (e) {
      this.get('flashes').error('There was an error while trying to active the repository.');
    }
  })
});

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

const { service } = Ember.inject;
const { alias } = Ember.computed;

import { task } from 'ember-concurrency';

export default Ember.Component.extend({
  auth: service(),
  flashes: service(),

  user: alias('auth.currentUser'),

  canActivate: Ember.computed('user.pushPermissions.[]', 'repo', function () {
    let user = this.get('user');
    if (user) {
      let permissions = user.get('pushPermissions'),
        repoId = parseInt(this.get('repo.id'));

      return permissions.contains(repoId);
    } else {
      return false;
    }
  }),

  activate: task(function* () {
    const apiEndpoint = config.apiEndpoint;
    const repoId = this.get('repo.id');

    try {
      const response = yield Ember.$.ajax(`${apiEndpoint}/v3/repo/${repoId}/enable`, {
        headers: {
          Authorization: `token ${this.get('auth').token()}`
        },
        method: 'POST'
      });

      if (response.active) {
        this.get('pusher').subscribe(`repo-${repoId}`);

        this.get('repo').set('active', true);
        this.get('flashes').success('Repository has been successfully activated.');
      }
    } catch (e) {
      this.get('flashes').error('There was an error while trying to activate the repository.');
    }
  })
});

Fix typo shown in flash when repo activation fails


// TODO make user specific
var OSF = 'user-osf-*';
var PARTICIPANT = 'jam-experimenter:accounts-*';
var GLOBAL = '*';

var config = [
    [OSF, 'CRUD']
];

var admin = [
    [OSF, 'READ'],
    [OSF, 'CREATE']
];

var experiment = [
    [GLOBAL, 'READ'],
    [OSF, 'CREATE']
];

var session = [
    [PARTICIPANT, 'CREATE'],
    [OSF, 'READ']
];

var account = [
    [GLOBAL, 'CREATE'],
    [OSF, 'READ']
];

var profile = [
    [PARTICIPANT, 'CREATE'],
    [OSF, 'READ']
];

var thumbnail = [
    [PARTICIPANT, 'READ'],
    [OSF, 'CREATE']
];

module.exports = {
    account: account,
    admin: admin,
    config: config,
    experiment: experiment,
    profile: profile,
    thumbnail: thumbnail
    // session: session
};

// TODO make user specific
var OSF = 'user-osf-*';
var PARTICIPANT = 'jam-experimenter:accounts-*';
var GLOBAL = '*';

var config = [
    [OSF, 'CRUD']
];

var admin = [
    [OSF, 'READ'],
    [OSF, 'CREATE']
];

var experiment = [
    [GLOBAL, 'READ'],
    [OSF, 'CREATE']
];

var session = [
    [PARTICIPANT, 'CREATE'],
    [PARTICIPANT, 'UPDATE'],
    [OSF, 'READ']
];

var account = [
    [GLOBAL, 'CREATE'],
    [OSF, 'READ']
];

var profile = [
    [PARTICIPANT, 'CREATE'],
    [OSF, 'READ']
];

var thumbnail = [
    [PARTICIPANT, 'READ'],
    [OSF, 'CREATE']
];

module.exports = {
    account: account,
    admin: admin,
    config: config,
    experiment: experiment,
    profile: profile,
    thumbnail: thumbnail
    // session: session
};

Make sure participants can update their sessions


const os = require('os')
const path = require('path')

let productName = 'Child Product'
let companyName = 'Child Company'
let tmpPath = path.join(os.tmpdir(), productName + ' Crashes')

process.crashReporter.start({
  productName: productName,
  companyName: companyName,
  submitURL: 'http://localhost:1127/post',
  crashesDirectory: tmpPath,
  extra: {
    randomData1: 'The Holidays are here!',
    randomData2: 'Happy New Year!'
  }
})
process.crash()

const os = require('os')
const path = require('path')
const {spawn} = require('child_process')

let submitURL = 'http://localhost:1127/post'
let productName = 'Child Product'
let companyName = 'Child Company'
let tmpPath = path.join(os.tmpdir(), productName + ' Crashes')

if (process.platform === 'win32') {
  const args = [
    '--reporter-url=' + submitURL,
    '--application-name=' + productName,
    '--crashes-directory=' + tmpPath
  ]
  const env = {
    ELECTRON_INTERNAL_CRASH_SERVICE: 1
  }
  spawn(process.execPath, args, {
    env: env,
    detached: true
  })
}

process.crashReporter.start({
  productName: productName,
  companyName: companyName,
  submitURL: submitURL,
  crashesDirectory: tmpPath,
  extra: {
    randomData1: 'The Holidays are here!',
    randomData2: 'Happy New Year!'
  }
})
process.crash()

Support crash reporting from child process in Windows


#!/usr/bin/env node
"use strict";

var pkg = require("../package.json");
var fs = require("fs");
var path = require("path");
var argv = require("yargs")
    .usage("Usage: squiggle --input [file] --output [file]")
    .option("input", {
        alias: "i",
        describe: "Read Squiggle from this file",
        nargs: 1,
        string: true,
        demand: true
    })
    .option("output", {
        alias: "o",
        describe: "Write JavaScript to this file",
        nargs: 1,
        string: true,
        demand: true
    })
    .option("help", {
        alias: "h",
        describe: "Print this message"
    })
    .version(pkg.version)
    .alias("version", "v")
    .epilogue("Version " + pkg.version)
    .showHelpOnFail(true)
    .strict()
    .argv;

var parse = require("./parse");
var transformAst = require("./transform-ast");
var compile = require("./compile");
var lint = require("./lint");

var UTF8 = "utf-8";

function die(message) {
    console.error("squiggle: error: " + message);
    process.exit(1);
}

var txt = fs.readFileSync(argv.input, "utf-8");
var ast = parse(txt);
var warnings = lint(ast);

warnings.forEach(function(m) {
    console.error('squiggle: lint: ' + m);
});

var es = transformAst(ast);
var code = compile(es);

fs.writeFileSync(argv.output, code, UTF8);

#!/usr/bin/env node
"use strict";

var pkg = require("../package.json");
var fs = require("fs");
var path = require("path");
var argv = require("yargs")
    .demand(1)
    .usage("Usage: squiggle [options] [file] --output [file]")
    .option("output", {
        alias: "o",
        describe: "Write JavaScript to this file",
        nargs: 1,
        string: true,
        demand: true
    })
    .option("help", {
        alias: "h",
        describe: "Print this message"
    })
    .version(pkg.version)
    .alias("version", "v")
    .epilogue("Version " + pkg.version)
    .showHelpOnFail(true)
    .strict()
    .argv;

var parse = require("./parse");
var transformAst = require("./transform-ast");
var compile = require("./compile");
var lint = require("./lint");

var UTF8 = "utf-8";

function die(message) {
    console.error("squiggle: error: " + message);
    process.exit(1);
}

var txt = fs.readFileSync(argv._[0], "utf-8");
var ast = parse(txt);
var warnings = lint(ast);

warnings.forEach(function(m) {
    console.error('squiggle: lint: ' + m);
});

var es = transformAst(ast);
var code = compile(es);

fs.writeFileSync(argv.output, code, UTF8);

Revert "Makes command line API more verbose"


'use strict';

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require('passport');

const config = require('./config/config');
const app = express();

function connect(options) {
  return mongoose.connect(config.db, options).connection;
}

function listen() {
  app.listen(config.port);

  // eslint-disable-next-line no-console
  console.log(`Express app started on http://127.0.0.1: ${config.port}`);
}

connect()
  // eslint-disable-next-line no-console
  .on('error', console.log)
  .on('disconnected', connect)
  .once('open', listen);

/**
 * Expose application
 */

module.exports = app;

// Configure application
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
require('./config/passport')(app, passport);

// Bootstrap routes
require('./config/routes')(app);

'use strict';

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require('passport');

const config = require('./config/config');
const app = express();

function connect(options) {
  return mongoose.connect(config.db, options).connection;
}

function listen() {
  app.listen(config.port);

  // eslint-disable-next-line no-console
  console.log(`Express app started on http://127.0.0.1:${config.port}`);
}

connect()
  // eslint-disable-next-line no-console
  .on('error', console.log)
  .on('disconnected', connect)
  .once('open', listen);

/**
 * Expose application
 */

module.exports = app;

// Configure application
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
require('./config/passport')(app, passport);

// Bootstrap routes
require('./config/routes')(app);

Remove space between host and port in console


'use strict';

import {Pipe} from 'angular2/core';
import {JsonPointer} from './JsonPointer';
import marked from 'marked';

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  smartLists: true,
  smartypants: false
});

@Pipe({
  name: 'keys'
})
export class KeysPipe {
  transform(obj) {
    return Object.keys(obj);
  }
}

@Pipe({
  name: 'values'
})
export class ValuesPipe {
  transform(obj) {
    return Object.keys(obj).map(key => obj[key]);
  }
}

@Pipe({
  name: 'jsonPointerEscape'
})
export class JsonPointerEscapePipe {
  transform(str) {
    return JsonPointer.escape(str);
  }
}

@Pipe({
  name: 'marked'
})
export class MarkedPipe {
  transform(str) {
    if (!str) return str;
    return marked(str);
  }
}

'use strict';

import {Pipe, InvalidPipeArgumentException} from 'angular2/core';
import {isString} from 'angular2/src/facade/lang';
import {JsonPointer} from './JsonPointer';
import marked from 'marked';

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  smartLists: true,
  smartypants: false
});

@Pipe({ name: 'keys' })
export class KeysPipe {
  transform(obj) {
    if (typeof obj !== 'object') {
      throw new InvalidPipeArgumentException(ValuesPipe, obj);
    }
    return Object.keys(obj);
  }
}

@Pipe({ name: 'values' })
export class ValuesPipe {
  transform(value) {
    if (typeof value !== 'object') {
      throw new InvalidPipeArgumentException(ValuesPipe, value);
    }
    return Object.keys(value).map(key => value[key]);
  }
}

@Pipe({ name: 'jsonPointerEscape' })
export class JsonPointerEscapePipe {
  transform(value) {
    if (!isString(value)) {
      throw new InvalidPipeArgumentException(JsonPointerEscapePipe, value);
    }
    return JsonPointer.escape(value);
  }
}

@Pipe({ name: 'marked' })
export class MarkedPipe {
  transform(value) {
    if (!isString(value)) {
      throw new InvalidPipeArgumentException(JsonPointerEscapePipe, value);
    }
    return marked(value);
  }
}

Add error messages to Pipes


$(document).ready(function(){
  // focus first field in an admin form.
  $('form input[type=text]:first').focus();

  init_flash_messages();
});

init_flash_messages = function(){
  $('#flash').css({
    'opacity': 0
    , 'visibility':'visible'
  }).animate({'opacity': '1'}, 550);
  $('#flash_close').click(function(e) {
    try {
      $('#flash').animate({
         'opacity': 0,
         'visibility': 'hidden'
      }, 330);
    } catch(ex) {
      $('#flash').hide();
    }
    e.preventDefault();
  });
  $('#flash.flash_message').prependTo('#records');
};

$(document).ready(function(){
  // focus first field in an admin form.
  $('form input[type=text]:first').focus();

  init_flash_messages();
});

init_flash_messages = function(){
  $('#flash').css({
    'opacity': 0
    , 'visibility':'visible'
  }).animate({'opacity': '1'}, 550);
  $('#flash_close').click(function(e) {
    try {
      $('#flash').animate({
         'opacity': 0,
         'visibility': 'hidden'
      }, 330, function() {
        $('#flash').hide();
      });
    } catch(ex) {
      $('#flash').hide();
    }
    e.preventDefault();
  });
  $('#flash.flash_message').prependTo('#records');
};

Hide the flash completely when the animation is completed. Closes GH-539


/**
 * Provides a global namespace for the Zinc javascript library and some default parameters for it.
 *
 * @namespace
 * @author Alan Wu
 */

var Zinc = function() {
  this.Revision = 29;

  this.defaultMaterialColor = 0xFFFFFF;
  this.defaultOpacity = 1.0;

  this.Geometry = require('./geometry').Geometry;
  this.Glyph = require('./glyph').Glyph;
  this.Glyphset = require('./glyphset').Glyphset;
  this.Renderer = require('./renderer').Renderer;
  this.Scene = require('./scene').Scene;
  this.GeometryCSG = require('./geometryCSG').GeometryCSG;

  this.Viewport = require('./controls').Viewport;
  this.CameraControls = require('./controls').CameraControls;
  this.SmoothCameraTransition = require('./controls').SmoothCameraTransition;
  this.RayCaster = require('./controls').RayCaster;
  this.CameraAutoTumble = require('./controls').CameraAutoTumble;
  this.loadExternalFile = require('./utilities').loadExternalFile;
  this.loadExternalFiles = require('./utilities').loadExternalFiles;
  this.StereoEffect = require('./controls').StereoEffect;

}

module.exports = new Zinc();

/**
 * Provides a global namespace for the Zinc javascript library and some default parameters for it.
 *
 * @namespace
 * @author Alan Wu
 */

var Zinc = function() {
  this.Revision = 29;

  this.defaultMaterialColor = 0xFFFFFF;
  this.defaultOpacity = 1.0;

  this.Geometry = require('./geometry').Geometry;
  this.Glyph = require('./glyph').Glyph;
  this.Glyphset = require('./glyphset').Glyphset;
  this.Renderer = require('./renderer').Renderer;
  this.Scene = require('./scene').Scene;
  this.GeometryCSG = require('./geometryCSG').GeometryCSG;

  this.Viewport = require('./controls').Viewport;
  this.CameraControls = require('./controls').CameraControls;
  this.SmoothCameraTransition = require('./controls').SmoothCameraTransition;
  this.RayCaster = require('./controls').RayCaster;
  this.CameraAutoTumble = require('./controls').CameraAutoTumble;
  this.loadExternalFile = require('./utilities').loadExternalFile;
  this.loadExternalFiles = require('./utilities').loadExternalFiles;
  this.StereoEffect = require('./controls').StereoEffect;
  this.THREE = require('three');

}

module.exports = new Zinc();

Add threejs library as one of the usable module for compatibility.


Threadable.realtime.connect = function(currentUser) {
  var userId = currentUser.get('userId');

  if (typeof io != 'undefined' && io !== null) {
    Threadable.realtime.socketIo = io.connect(Threadable.realtime.url + '/?userId=' + userId + '&token=' + Threadable.realtime.token);
  }

  if (Threadable.realtime.socketIo) {
    Threadable.realtime.socketIo.on('connect', function() {
      Threadable.realtime.socketIo.emit('realtime_user_id_connected', { userId: userId });
    });

    Threadable.realtime.socketIo.on('application_update', function(message) {
      // camelize the keys.
      Object.keys(message).map(function(key) {
        var value = message[key];
        delete message[key];
        message[Ember.String.camelize(key)] = value;
      }, this);

      var update = Threadable.ApplicationUpdate.create(message);
      currentUser.get('applicationUpdates').pushObject(update);
    });
  }
};

Threadable.realtime.connect = function(currentUser) {
  var userId = currentUser.get('userId');

  if (typeof io != 'undefined' && io !== null) {
    Threadable.realtime.socketIo = io.connect(Threadable.realtime.url + '/?userId=' + userId + '&token=' + Threadable.realtime.token);
  }

  if (Threadable.realtime.socketIo) {
    Threadable.realtime.socketIo.on('connect', function() {
      Threadable.realtime.socketIo.emit('realtime_user_id_connected', { userId: userId });

      setInterval(function() {
        Threadable.realtime.socketIo.emit('ping');
      }, 10*1000);
    });

    Threadable.realtime.socketIo.on('application_update', function(message) {
      // camelize the keys.
      Object.keys(message).map(function(key) {
        var value = message[key];
        delete message[key];
        message[Ember.String.camelize(key)] = value;
      }, this);

      var update = Threadable.ApplicationUpdate.create(message);
      currentUser.get('applicationUpdates').pushObject(update);
    });

    Threadable.realtime.socketIo.on('pong', function(message) {
      // do nothing for now. but these do come back.
    });
  }
};

Send ping/pong to keep the connection open.


/*
 * Copyright(c) 2014, Unional (https://github.com/unional)
 * @license Licensed under the MIT License (https://github.com/unional/umd/LICENSE)).
 * Created by unional on 9/21/14.
 */
umd(function(define) {
    define(function(require) {
        var func = require('sampleModules/umd/defineFunction');
        var func2 = require('sampleModules/umdv/defineFunction');

        return function() {
            return func() + " " + func2();
        }
    });
}, "sampleModules.umd.defineFunctionWithDep", require, exports, module);

/*
 * Copyright(c) 2014, Unional (https://github.com/unional)
 * @license Licensed under the MIT License (https://github.com/unional/umd/LICENSE)).
 * Created by unional on 9/21/14.
 */
umd(function(define) {
    define(function(require) {
        var func = require('sampleModules/umd/defineFunction');
        var func2 = require('sampleModules/umdv/defineFunction');

        return function() {
            return func() + " " + func2();
        }
    });

    return {
        nodeJS: {
            "sampleModules/umd/defineFunction": "./defineFunction",
            "sampleModules/umdv/defineFunction": "../umdv/defineFunction"
        }
    };
}, "sampleModules.umd.defineFunctionWithDep", require, exports, module);

Add return to definition function. The return value will be used to map the require calls. Not implemented yet.


'use strict';

// changeable contants
var C = 'constructor', // name of the constructor method
	X = 'extend'; // name of extend method

function Class() {}

Class[X] = function(subclass) {
	var prototype = Object.create(this.prototype);

	subclass.call(prototype, this.prototype);

	var Extended = prototype.hasOwnProperty(C) ?
		prototype[C] :
		function() { prototype[C].apply(this, arguments); };

	Extended.prototype = prototype;
	Extended[X] = this[X];

	return Extended;
};

'use strict';

// changeable contants
var C = 'constructor', // name of the constructor method
	X = 'extend'; // name of extend method

function Class() {}

Class[X] = function(subclass) {
	var prototype = Object.create(this.prototype);

	subclass.call(prototype, this.prototype);

	function Extended() {
		prototype[C].apply(this, arguments);
	}
	Extended.prototype = prototype;
	Extended[X] = this[X];

	return Extended;
};

Remove unnecessary own property check


/**
 * Detects if only the primary button has been clicked in mouse events.
 * @param {MouseEvent} e Event instance (or Event-like, i.e. `SyntheticEvent`)
 * @return {Boolean}
 */
export const isPrimaryClick = e =>
  !(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) &&
  (!("buttons" in e) || e.buttons === 0 || e.buttons === 1) &&
  ("button" in e ? e.button === 0 : e.which === 1);

/**
 * Decorates a function so it calls if only the primary button has been
 * pressed in mouse events.
 * @param {Function} fn
 * @return {Function}
 */
export const onPrimaryClick = fn => (e, ...args) =>
  isPrimaryClick(e) ? fn(e, ...args) : true;

/**
 * Detects if only the primary button has been clicked in mouse events.
 * @param {MouseEvent} e Event instance (or Event-like, i.e. `SyntheticEvent`)
 * @return {Boolean}
 */
export const isPrimaryClick = e =>
  !(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) &&
  (e.buttons == null || e.buttons === 0 || e.buttons === 1) &&
  (e.buttons != null ? e.button === 0 : e.which === 1);

/**
 * Decorates a function so it calls if only the primary button has been
 * pressed in mouse events.
 * @param {Function} fn
 * @return {Function}
 */
export const onPrimaryClick = fn => (e, ...args) =>
  isPrimaryClick(e) ? fn(e, ...args) : true;

Use `== null` check instead of `in` because jQuery.Event defaults to undefined


import fs from 'fs'
import _ from 'lodash'
import postcss from 'postcss'
import stylefmt from 'stylefmt'

import defaultConfig from './defaultConfig'
import mergeConfig from './util/mergeConfig'

import generateUtilities from './lib/generateUtilities'
import substituteHoverableAtRules from './lib/substituteHoverableAtRules'
import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import substituteBreakpointAtRules from './lib/substituteBreakpointAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'

const plugin = postcss.plugin('tailwind', (options = {}) => {
  return (root, result) => {
    if (_.isFunction(options)) {
      options = options()
    }

    const config = mergeConfig(defaultConfig, options)

    return postcss([
      generateUtilities(config),
      substituteHoverableAtRules(config),
      substituteResponsiveAtRules(config),
      substituteBreakpointAtRules(config),
      substituteClassApplyAtRules(config),
      stylefmt,
    ]).process(result)
  }
})

module.exports = plugin

import fs from 'fs'
import _ from 'lodash'
import postcss from 'postcss'
import stylefmt from 'stylefmt'

import defaultConfig from './defaultConfig'
import mergeConfig from './util/mergeConfig'

import generateUtilities from './lib/generateUtilities'
import substituteHoverableAtRules from './lib/substituteHoverableAtRules'
import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import substituteBreakpointAtRules from './lib/substituteBreakpointAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'

const plugin = postcss.plugin('tailwind', (options = {}) => {
  if (_.isFunction(options)) {
    options = options()
  }

  const config = mergeConfig(defaultConfig, options)

  return postcss([
    generateUtilities(config),
    substituteHoverableAtRules(config),
    substituteResponsiveAtRules(config),
    substituteBreakpointAtRules(config),
    substituteClassApplyAtRules(config),
    stylefmt,
  ])
})

module.exports = plugin

Revert "Make config loading even lazier"


/*global Modernizr: true*/
var REIN = (function () {
    var modules = {}, events = {}, init, module, View;

    _.extend(events, Backbone.Events, {
        onMultiple: function (eNameToFnMap, ctx) {
            _.each(eNameToFnMap, function (fn, eventName) {
                this.on(eventName, fn, ctx);
            }, this);
        }
    });

    module = function (name) {
        if (modules[name]) {
            return modules[name];
        }

        modules[name] = { Views: {}, Models: {}, Collections: {} };
        return modules[name];
    };

    View = Backbone.View.extend({
        delegateEvents: function (events) {
            if (!(events || (events = this.events))) {
                return;
            }
            var key, tapEvents = _.extend({}, events);
            if (Modernizr.touch) {
                for (key in tapEvents) {
                    if (key.indexOf('click') > -1) {
                        tapEvents[key.replace('click', 'tap')] = tapEvents[key];
                        delete tapEvents[key];
                    }
                }
            }
            Backbone.View.prototype.delegateEvents.call(this, tapEvents);
        }
    });

    return {
        module: module,
        View: View,
        events: events
    };
}());

/*global Modernizr: true*/
var REIN = (function () {
    var modules = {}, events = {}, init, module, View;

    _.extend(events, Backbone.Events, {
        onMultiple: function (eNameToFnMap, ctx) {
            _.each(eNameToFnMap, function (fn, eventName) {
                this.on(eventName, fn, ctx);
            }, this);
        }
    });

    module = function (name) {
        if (modules[name]) {
            return modules[name];
        }

        modules[name] = { Views: {}, Models: {}, Collections: {} };
        return modules[name];
    };

    return {
        module: module,
        View: Backbone.View,
        events: events
    };
}());

Remove touch delay iPhone fix


//@flow

declare type Theme = {
  type: {
    ["title" | "heading" | "paragraph" | "label"]: string
  },
  scale: {
    ["s1" | "s2" | "s3" | "s4"]: (n: number) => string
  },
  color: {
    ["background" | "black" | "primary"]: string
  }
};

declare var module: {
  hot: {
    accept(path: Class<React$Component<*, *, *>>, callback: () => void): void
  }
};

Include webpack module type declaration


describe('Nodes Side Panel', function () {

  beforeEach(function () {
    cy.configureCluster({
      mesos: '1-task-healthy',
      nodeHealth: true
    })
  });

  context('Navigate to side panel', function () {

    it('navigates to node side panel', function () {
      cy.visitUrl({url: '/nodes', identify: true, fakeAnalytics: true});
      cy.get('tr a').contains('dcos-01').click();

      cy.hash().should('match', /node-detail/);
      cy.get('.side-panel-content-header h1').should(function ($title) {
        expect($title).to.contain('dcos-01');
      });
    });

    it('shows error in side panel when node is invalid [10a]', function () {
      cy.visitUrl({url: '/nodes/list/node-detail/INVALID_NODE', identify: true, fakeAnalytics: true});

      cy.hash().should('match', /node-detail/);
      cy.get('.side-panel-content h3').should(function ($title) {
        expect($title).to.contain('Error finding node');
      });
    });
  });

});

describe('Nodes Side Panel', function () {

  beforeEach(function () {
    cy.configureCluster({
      mesos: '1-task-healthy',
      nodeHealth: true
    })
  });

  context('Navigate to node detail page', function () {

    it('navigates to node side panel', function () {
      cy.visitUrl({url: '/nodes', identify: true, fakeAnalytics: true});
      cy.get('tr a').contains('dcos-01').click();

      cy.hash().should('match', /nodes\/[a-zA-Z0-9-]+/);
      cy.get('.page-content h1').should(function ($title) {
        expect($title).to.contain('dcos-01');
      });
    });

    it('shows error in side panel when node is invalid [10a]', function () {
      cy.visitUrl({url: '/nodes/INVALID_NODE', identify: true, fakeAnalytics: true});

      cy.hash().should('match', /nodes\/INVALID_NODE/);
      cy.get('.page-content h3').should(function ($title) {
        expect($title).to.contain('Error finding node');
      });
    });
  });

});

Fix nodes side panel contents integration tests


#!/usr/bin/env node

'use strict';

/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
process.title = 'polymer';

const resolve = require('resolve');
const updateNotifier = require('update-notifier');
const packageJson = require('../package.json');

// Update Notifier: Asynchronously check for package updates and, if needed,
// notify on the next time the CLI is run.
// See https://github.com/yeoman/update-notifier#how for how this works.
updateNotifier({pkg: packageJson}).notify();

resolve('polymer-cli', {basedir: process.cwd()}, function(error, path) {
  let lib = path ? require(path) : require('..');
  let args = process.argv.slice(2);
  let cli = new lib.PolymerCli(args);
  cli.run()
  .then(null, () => process.exit(1));
});

#!/usr/bin/env node

'use strict';

/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
process.title = 'polymer';

const resolve = require('resolve');
const updateNotifier = require('update-notifier');
const packageJson = require('../package.json');
const logging = require('plylog');

const logger = logging.getLogger('cli.main');

// Update Notifier: Asynchronously check for package updates and, if needed,
// notify on the next time the CLI is run.
// See https://github.com/yeoman/update-notifier#how for how this works.
updateNotifier({pkg: packageJson}).notify();

resolve('polymer-cli', {basedir: process.cwd()}, function(error, path) {
  let lib = path ? require(path) : require('..');
  let args = process.argv.slice(2);
  let cli = new lib.PolymerCli(args);
  cli.run().catch(err => {
    logger.error(err);
    if (err.stack) logger.error(err.stack);
    process.exit(1);
  });
});

Use catch instead of then and log message before exit


(function () {
  angular.module('ui.grid').config(['$provide', function($provide) {
    $provide.decorator('i18nService', ['$delegate', function($delegate) {
      $delegate.add('nl', {
        aggregate: {
          label: 'items'
        },
        groupPanel: {
          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
        },
        search: {
          placeholder: 'Zoeken...',
          showingItems: 'Getoonde items:',
          selectedItems: 'Geselecteerde items:',
          totalItems: 'Totaal aantal items:',
          size: 'Items per pagina:',
          first: 'Eerste pagina',
          next: 'Volgende pagina',
          previous: 'Vorige pagina',
          last: 'Laatste pagina'
        },
        menu: {
          text: 'Kies kolommen:'
        },
        sort: {
          ascending: 'Sorteer oplopend',
          descending: 'Sorteer aflopend',
          remove: 'Verwijder sortering'
        },
        column: {
          hide: 'Verberg kolom'
        },
        aggregation: {
          count: 'total rows: ',
          sum: 'total: ',
          avg: 'avg: ',
          min: 'min: ',
          max: 'max: '
        }
      });
      return $delegate;
    }]);
  }]);
})();

(function () {
  angular.module('ui.grid').config(['$provide', function($provide) {
    $provide.decorator('i18nService', ['$delegate', function($delegate) {
      $delegate.add('nl', {
        aggregate: {
          label: 'items'
        },
        groupPanel: {
          description: 'Sleep hier een kolomnaam heen om op te groeperen.'
        },
        search: {
          placeholder: 'Zoeken...',
          showingItems: 'Getoonde items:',
          selectedItems: 'Geselecteerde items:',
          totalItems: 'Totaal aantal items:',
          size: 'Items per pagina:',
          first: 'Eerste pagina',
          next: 'Volgende pagina',
          previous: 'Vorige pagina',
          last: 'Laatste pagina'
        },
        menu: {
          text: 'Kies kolommen:'
        },
        sort: {
          ascending: 'Sorteer oplopend',
          descending: 'Sorteer aflopend',
          remove: 'Verwijder sortering'
        },
        column: {
          hide: 'Verberg kolom'
        },
        aggregation: {
          count: 'aantal rijen: ',
          sum: 'som: ',
          avg: 'gemiddelde: ',
          min: 'min: ',
          max: 'max: '
        }
      });
      return $delegate;
    }]);
  }]);
})();

Add dutch translation for aggregation


'use strict';

/**
 * @module providers
 */

var util = require('util');
var EntityProvider = process.requireAPI('lib/providers/EntityProvider.js');

/**
 * Defines a TaxonomyProvider class to get and save taxonomies.
 *
 * @class TaxonomyProvider
 * @constructor
 * @extends EntityProvider
 * @param {Database} database The database to interact with
 */
function TaxonomyProvider(database) {
  EntityProvider.call(this, database, 'taxonomy');
}

module.exports = TaxonomyProvider;
util.inherits(TaxonomyProvider, EntityProvider);

/**
 * Creates taxonomies indexes.
 *
 * @method createIndexes
 * @async
 * @param {Function} callback Function to call when it's done with :
 *  - **Error** An error if something went wrong, null otherwise
 */
TaxonomyProvider.prototype.createIndexes = function(callback) {
  this.database.createIndexes(this.collection, [
    {key: {name: 1}, name: 'byName'}
  ], function(error, result) {
    if (result && result.note)
      process.logger.debug('Create taxonomies indexes : ' + result.note);

    callback(error);
  });
};

'use strict';

/**
 * @module providers
 */

var util = require('util');
var EntityProvider = process.requireAPI('lib/providers/EntityProvider.js');

/**
 * Defines a TaxonomyProvider class to get and save taxonomies.
 *
 * @class TaxonomyProvider
 * @constructor
 * @extends EntityProvider
 * @param {Database} database The database to interact with
 */
function TaxonomyProvider(database) {
  EntityProvider.call(this, database, 'taxonomy');
}

module.exports = TaxonomyProvider;
util.inherits(TaxonomyProvider, EntityProvider);

/**
 * Creates taxonomies indexes.
 *
 * @method createIndexes
 * @async
 * @param {Function} callback Function to call when it's done with :
 *  - **Error** An error if something went wrong, null otherwise
 */
TaxonomyProvider.prototype.createIndexes = function(callback) {
  this.database.createIndexes(this.collection, [
    {key: {name: 1}, name: 'byName'},
    {key: {name: 'text'}, weights: {name: 1}, name: 'querySearch'}
  ], function(error, result) {
    if (result && result.note)
      process.logger.debug('Create taxonomies indexes : ' + result.note);

    callback(error);
  });
};

Add search index for the taxonomy collection


const CronJob = require('cron').CronJob;
const splatnet = require('./splatnet');

console.info('Starting periodic tasks...');

// Run every day at 0min 30sec after the hour
new CronJob('30 0 * * * *', () => {
    splatnet.update();
}, null, true);

const CronJob = require('cron').CronJob;
const splatnet = require('./splatnet');
const salmoncalendar = require('./salmoncalendar');

console.info('Starting periodic tasks...');

// Run every day at 0min 30sec after the hour
new CronJob('30 0 * * * *', () => {
    splatnet.update();
    salmoncalendar.update();
}, null, true);

Add the Salmon Run calendar to the hourly update script


import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import api from './api';

let server = null;

function start(port) {
    return new Promise((resolve, reject) => {
        if (server !== null) {
            reject(new Error('The server is already running.'));
        }
        let app = express();
        app.use(express.static(path.join(__dirname, '../public')));
        app.use(bodyParser.json({ limit: '1.5MB' }));
        app.use('/api', api);
        server = app.listen(port, () => {
            resolve();
        });
    });
}

function stop() {
    return new Promise((resolve, reject) => {
        if (server === null) {
            reject(new Error('The server is not running.'));
        }
        server.close(() => {
            server = null;
            resolve();
        });
    });
}

export default {
    start,
    stop
};

import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import api from './api';

let server = null;

function start(port) {
    return new Promise((resolve, reject) => {
        if (server !== null) {
            reject(new Error('The server is already running.'));
        }
        let app = express();
        app.use(express.static(path.join(__dirname, '../public')));
        app.use(bodyParser.json({ limit: '1MB' }));
        app.use('/api', api);
        server = app.listen(port, () => {
            resolve();
        });
    });
}

function stop() {
    return new Promise((resolve, reject) => {
        if (server === null) {
            reject(new Error('The server is not running.'));
        }
        server.close(() => {
            server = null;
            resolve();
        });
    });
}

export default {
    start,
    stop
};

Revert "Increase payload limit to 1.5MB"


import 'core-js';
import 'normalize.css';
import './index.scss';
import { isDuringLiffRedirect } from './lib';
import App from './App.svelte';

liff.init({ liffId: LIFF_ID }).then(() => {
  // liff.init should have corrected the path now, don't initialize app and just wait...
  // Ref: https://www.facebook.com/groups/linebot/permalink/2380490388948200/?comment_id=2380868955577010
  if (isDuringLiffRedirect) return;

  if (!liff.isLoggedIn()) {
    liff.login({
      // https://github.com/line/line-liff-v2-starter/issues/4
      redirectUri: `${location.href}${location.search}`,
    });
  }

  // Cleanup loading
  document.getElementById('loading').remove();
  new App({ target: document.body });
});

import 'core-js';
import 'normalize.css';
import './index.scss';
import { isDuringLiffRedirect } from './lib';
import App from './App.svelte';

liff.init({ liffId: LIFF_ID }).then(() => {
  // liff.init should have corrected the path now, don't initialize app and just wait...
  // Ref: https://www.facebook.com/groups/linebot/permalink/2380490388948200/?comment_id=2380868955577010
  if (isDuringLiffRedirect) return;

  document.getElementById('loading').remove(); // Cleanup loading

  // Kickstart app loading; fire assertions
  new App({ target: document.body });

  // For devs (and users on LINE desktop, which is rare)
  if (!liff.isLoggedIn()) {
    liff.login({
      // https://github.com/line/line-liff-v2-starter/issues/4
      redirectUri: location.href,
    });
  }
});

Fix LINE login procedure: 1. First fire App() so that assertions are not interrupted by LINE login 2. LINE login redirect URI fix: location.href already includes location.search. Repeating that will result in incorrect url token


import Ember from 'ember';

export default Ember.Mixin.create({
    get : function( key ){
        var translationsRegex = /translate\.(.*)/,
            matches = key.match( translationsRegex );
        if( matches ){
            return this.translate( matches[1] );
        }
        return this._super( key );
    },

    translate: function( key ){
        return this.translateService.getKeyValue( key );
    }
});

import Ember from 'ember';

export default Ember.Mixin.create({
    get: function( key ) {
        var translationsRegex = /translate\.(.*)/,
            matches           = key.match( translationsRegex );

        return ( matches ) ? this.translate( matches[1] ) : this._super( key );
    },

    translate: function( key ) {
        return this.translateService.getKeyValue( key );
    }
});

Refactor to follow style guidelines


import React from 'react';

const UserApp = () => (

UserApp Page

);

export default UserApp;

import React from 'react';

const UserApp = () => (

UserApp Page

Sign Out

);

export default UserApp;

Add sign out button to user app


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require turbolinks
//= require jquery3
//= require jquery_ujs
//= require foundation
//= require_tree .

$(document).on('turbolinks:load', function() {
  $(document).foundation();
  $('[data-open="ajax-reveal"]').on('click', function(e) {
    e.preventDefault();
    $.ajax({
      url: $(this).data('url'),
      success: function(result) {
        $(".reveal-content").html(result);
      },
      error: function(result) {
        $(".reveal-content").html('Error loading content. Please close popup and retry.');
      }
    });
  });
});

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require turbolinks
//= require jquery3
//= require jquery_ujs
//= require foundation
//= require_tree .

$(document).on('turbolinks:load', function() {
  $(document).foundation();
  $('body').on('click', '[data-open="ajax-reveal"]', function(e) {
    e.preventDefault();
    $.ajax({
      url: $(this).data('url'),
      success: function(result) {
        $(".reveal-content").html(result);
      },
      error: function(result) {
        $(".reveal-content").html('Error loading content. Please close popup and retry.');
      }
    });
  });
});

Modify ajax-reveal to open modal from a link on modal


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require webflow
//= require modernizr
//= require jquery-waypoints/waypoints.min
//= require landing
//= require enter_details
//= require bootstrap

Load the bootstrap js plugins


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require turbolinks
//= require jquery
//= require jquery_ujs
//= require jquery.turbolinks
//= require local_time
//= require jquery.purr
//= require best_in_place

$(document).ready(function() {
     /* Activating Best In Place */
     jQuery(".best_in_place").best_in_place()
});

$(document).ready(function() {
   $('img').each( function() {
      var o = $(this);
      if( ! o.attr('title') && o.attr('alt') ) o.attr('title', o.attr('alt') );
   });
});

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require local_time
//= require jquery.purr
//= require best_in_place

$(document).ready(function() {
     /* Activating Best In Place */
     jQuery(".best_in_place").best_in_place()
});

$(document).ready(function() {
   $('img').each( function() {
      var o = $(this);
      if( ! o.attr('title') && o.attr('alt') ) o.attr('title', o.attr('alt') );
   });
});

Remove turbo links since it messes up my unskilled javascript.


'use babel';

export default {
  ENV: (process.env.NODE_ENV === 'development' ? 'DEV' : 'PROD'),
  ERROR_ICON:'✖',
  SUCCESS_ICON:'✔',
  CARD_SUCCESS_CLASS: 'success',
  CARD_ERROR_CLASS: 'error',
  BUILD_STATUS_SUCCESS: 'Success'
};

'use babel';

export default {
  ENV: (process.env.NODE_ENV === 'development' ? 'DEV' : 'PROD'),
  PENDING_ICON:'•••',
  ERROR_ICON:'✖',
  SUCCESS_ICON:'✔',
  CARD_SUCCESS_CLASS: 'success',
  CARD_ERROR_CLASS: 'error',
  CARD_PENDING_CLASS: 'pending',
  CARD_UNKNOWN_CLASS: 'unknown',
  BUILD_STATUS_SUCCESS: 'Success',
  BUILD_STATUS_FAILURE: 'Failure',
  BUILD_STATUS_PENDING: 'Pending',
  BUILD_STATUS_EXCEPTION: 'Exception',
  BUILD_STATUS_UNKNOWN: 'Unknown'
};

Add new constants for status and icons


'use strict';

const handelbars = require('handlebars');
const fs = require('fs');
const path = require('path');

const nodemailer = require('nodemailer');
require('env2')(`${__dirname}/../.env`);

// create reusable transporter object using the default SMTP transport
const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.EMAIL,
    pass: process.env.PASS
  }
});

function sendMail(emailAddress, emailContent, cb){

  const emailTemplate = fs.readFileSync(path.join(__dirname, 'templates', 'views', 'email.hbs'), 'utf8');
  const template = handelbars.compile(emailTemplate);
  const emailBody = template(emailContent);

  const mailOptions = {
    from: '"CAMHS 😀" <welcome.to.cahms@hotmail.co.uk>',
    subject: 'Getting to know you Questionnaire',
    text: 'Questionnaire',
    html: emailBody,
    to: emailAddress
  };

  transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
      return cb(error);
    }
    return cb(null, `Message ${info.messageId} sent: ${info.response}`);
  });
}

module.exports = sendMail;

'use strict';

const handelbars = require('handlebars');
const fs = require('fs');
const path = require('path');

const nodemailer = require('nodemailer');
require('env2')(`${__dirname}/../.env`);

// create reusable transporter object using the default SMTP transport
const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.EMAIL,
    pass: process.env.PASS
  }
});

function sendMail(emailAddress, emailContent, cb){

  const emailTemplate = fs.readFileSync(path.join(__dirname, 'templates', 'views', 'email.hbs'), 'utf8');
  const template = handelbars.compile(emailTemplate);
  const emailBody = template(emailContent);

  const mailOptions = {
    from: '"CAMHS 😀" <welcome.to.cahms@gmail.com>',
    subject: 'Getting to know you Questionnaire',
    text: 'Questionnaire',
    html: emailBody,
    to: emailAddress
  };

  transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
      return cb(error);
    }
    return cb(null, `Message ${info.messageId} sent: ${info.response}`);
  });
}

module.exports = sendMail;

Add correct 'from' email address on SendEmail function.


const Eknc = imports.gi.EosKnowledgeContent;

const InstanceOfMatcher = imports.tests.InstanceOfMatcher;

describe('Dictionary Object Model', function() {
    let dictionaryObject, jsonld;

    beforeEach(function() {
        jasmine.addMatchers(InstanceOfMatcher.customMatchers);

        jsonld = {
            '@id': 'ekn:word/Entreaty',
            'word': 'entreaty',
            'definition': 'An earnest request or petition; a plea.',
            'partOfSpeech': 'noun',
            'title': 'June 23rd',
        };
        dictionaryObject = Eknc.DictionaryObjectModel.new_from_json(jsonld);
    });

    describe('type', function() {
        it('should be a ContentObjectModel', function() {
            expect(dictionaryObject).toBeA(Eknc.ContentObjectModel);
        });

        it('should be a DictionaryObjectModel', function() {
            expect(dictionaryObject).toBeA(Eknc.DictionaryObjectModel);
        });
    });

    describe('JSON-LD marshaler', function() {
        it('should construct from a JSON-LD document', function() {
            expect(dictionaryObject).toBeDefined();
        });

        it('should marshal properties', function() {
            expect(dictionaryObject.word).toBe('entreaty');
            expect(dictionaryObject.definition).toBe('An earnest request or petition; a plea.');
            expect(dictionaryObject.part-of-speech).toBe('noun');
        });

        it('should inherit properties set by parent class (ContentObjectModel)', function() {
            expect(dictionaryObject.title).toBe('June 23rd');
        });
    });
});

const Eknc = imports.gi.EosKnowledgeContent;

const InstanceOfMatcher = imports.tests.InstanceOfMatcher;

describe('Dictionary Object Model', function() {
    let dictionaryObject, jsonld;

    beforeEach(function() {
        jasmine.addMatchers(InstanceOfMatcher.customMatchers);

        jsonld = {
            '@id': 'ekn:word/Entreaty',
            'word': 'entreaty',
            'definition': 'An earnest request or petition; a plea.',
            'partOfSpeech': 'noun',
            'title': 'June 23rd',
        };
        dictionaryObject = Eknc.DictionaryObjectModel.new_from_json(jsonld);
    });

    describe('type', function() {
        it('should be a ContentObjectModel', function() {
            expect(dictionaryObject).toBeA(Eknc.ContentObjectModel);
        });

        it('should be a DictionaryObjectModel', function() {
            expect(dictionaryObject).toBeA(Eknc.DictionaryObjectModel);
        });
    });

    describe('JSON-LD marshaler', function() {
        it('should construct from a JSON-LD document', function() {
            expect(dictionaryObject).toBeDefined();
        });

        it('should marshal properties', function() {
            expect(dictionaryObject.word).toBe('entreaty');
            expect(dictionaryObject.definition).toBe('An earnest request or petition; a plea.');
            expect(dictionaryObject.part_of_speech).toBe('noun');
        });

        it('should inherit properties set by parent class (ContentObjectModel)', function() {
            expect(dictionaryObject.title).toBe('June 23rd');
        });
    });
});

Test DictionaryObjectModel: correct usage of property


pageflow.ConfigurationEditorView.register('audio_loop', {
  configure: function() {
    this.tab('general', function() {
      this.group('general');

      this.input('additional_title', pageflow.TextInputView);
      this.input('additional_description', pageflow.TextAreaInputView, {size: 'short'});
    });

    this.tab('files', function() {
      this.input('audio_file_id', pageflow.FileInputView, {collection: pageflow.audioFiles});
      this.input('background_image_id', pageflow.FileInputView, {collection: pageflow.imageFiles});
      this.input('thumbnail_image_id', pageflow.FileInputView, {
        collection: pageflow.imageFiles,
        positioning: false
      });
    });

    this.tab('options', function() {
      this.group('options');
    });
  }
});

pageflow.ConfigurationEditorView.register('audio_loop', {
  configure: function() {
    this.tab('general', function() {
      this.group('general');
    });

    this.tab('files', function() {
      this.input('audio_file_id', pageflow.FileInputView, {collection: pageflow.audioFiles});
      this.input('background_image_id', pageflow.FileInputView, {collection: pageflow.imageFiles});
      this.input('thumbnail_image_id', pageflow.FileInputView, {
        collection: pageflow.imageFiles,
        positioning: false
      });
    });

    this.tab('options', function() {
      this.group('options');
    });
  }
});

Remove Additional Info Box Fields for Audio Loop Page


module.exports = function (bot) {
    bot.on('modMute', function (data) {
        if (config.verboseLogging) {
            console.log('[EVENT] modMute ', JSON.stringify(data, null, 2));
        }

        var duration = 'unknown';
        switch (data.d) {
            case 's':
                duration = '15';
                break;
            case 'm':
                duration = '30';
                break;
            case 'l':
                duration = '45';
                break;
        }

        getDbUserFromUsername(data.t, function (dbUser) {
            var message;
            if (dbUser == null) {
                message = '[MUTE] ' + data.t + ' (ID: ' + data.i + ') was muted for ' + duration + ' minutes by ' + data.m;
                message = '[MUTE] ' + data.t + ' (ID: ' + data.i + ') was muted for ' + duration + ' minutes by ' + data.m;
            } else {
                message = '[BAN] ' + data.t + ' (ID: ' + data.i + ', LVL: ' + dbUser.site_points + ') was muted for ' + duration + ' minutes by ' + data.m;
            }
            console.log(message);
            sendToSlack(message);
        });
    });
};

module.exports = function (bot) {
    bot.on('modMute', function (data) {
        if (config.verboseLogging) {
            console.log('[EVENT] modMute ', JSON.stringify(data, null, 2));
        }

        var duration = 'unknown';
        switch (data.d) {
            case 's':
                duration = '15';
                break;
            case 'm':
                duration = '30';
                break;
            case 'l':
                duration = '45';
                break;
            default:
                // maybe this is an unmute?
                break;
        }

        getDbUserFromUsername(data.t, function (dbUser) {
            var message;
            if (duration == 'unknown') {
                message = '[UNMUTE] ' + data.t + ' (ID:' + data.i + ') was unmuted by ' + data.m;
            } else if (dbUser == null) {
                message = '[MUTE] ' + data.t + ' (ID:' + data.i + ') was muted for ' + duration + ' minutes by ' + data.m;
            } else {
                message = '[MUTE] ' + data.t + ' (ID:' + data.i + ', LVL:' + dbUser.site_points + ') was muted for ' + duration + ' minutes by ' + data.m;
            }
            console.log(message);
            sendToSlack(message);
        });
    });
};

Add in handling for a user being unmuted


var canvas,
	ctx,
	input,
	info;

window.onload = function(){
	canvas = document.getElementById("canvas");
	ctx = canvas.getContext('2d');

	input = document.getElementById("input");
	info = document.getElementById("info");

	input.onkeyup = newUPC;

	newUPC();
}

function newUPC(){

	var text = input.value;

	ctx.clearRect(0,0,1000,100);

	var ean = new EAN(text);
	var code128 = new Code128(text);

	if(ean.valid()){
		drawBinary(ean.encoded(), ctx, 100, 2);
		info.innerHTML = "Using EAN13";
	}
	else if(code128.valid()){
		drawBinary(code128.encoded(), ctx, 100, 2);
		info.innerHTML = "Using Code128";
	}
	else{
		info.innerHTML = "Not a supported input!";
	}

}

var canvas,
	ctx,
	input,
	info;

window.onload = function(){
	canvas = document.getElementById("canvas");
	ctx = canvas.getContext('2d');

	input = document.getElementById("input");
	info = document.getElementById("info");

	input.onkeyup = newUPC;

	newUPC();
}

function newUPC(){

	var text = input.value;

	ctx.clearRect(0,0,1000,100);

	var ean = new EAN(text);
	var code128 = new CODE128(text);

	if(ean.valid()){
		drawBinary(ean.encoded(), ctx);
		info.innerHTML = "Using EAN13";
	}
	else if(code128.valid()){
		drawBinary(code128.encoded(), ctx, {width:1,height:20});
		info.innerHTML = "Using Code128";
	}
	else{
		info.innerHTML = "Not a supported input!";
	}

}

Update to example with new optional arguments


const HTMLHint = require("htmlhint").HTMLHint

module.exports = function () {
  this.filter("htmlhint", (source, options) => {
    try {
      const messages = HTMLHint(source, options)
      console.log(messages)
      return source
     } catch (e) { throw e }
  }, { ext: ".html" })
}

const htmlhint = require("htmlhint").HTMLHint

module.exports = function () {
  this.filter("htmlhint", (source, options) => {
    try {
      const messages = htmlhint(source, options)
      console.log(messages)
      return source
     } catch (e) { throw e }
  }, { ext: ".html" })
}

Change to lowercase name for eslint


'use strict';

var assign = require('object-assign');

hexo.config.category_generator = assign({
  per_page: hexo.config.per_page || 10
}, hexo.config.category_generator);

hexo.extend.generator.register('category', require('./lib/generator'));

'use strict';

var assign = require('object-assign');

hexo.config.category_generator = assign({
  per_page: typeof hexo.config.per_page === "undefined" ? 10 : hexo.config.per_page
}, hexo.config.category_generator);

hexo.extend.generator.register('category', require('./lib/generator'));

Allow users to set the per_page option to 0


Append suffix "-loader" to each loaders for webpack2


fs = require('fs')
req    = require('request')
server = require('node-router').getServer()

server.get("/", function(request, response){
    fs.readFile(__dirname + '/index.html', function(err, data){
        response.writeHead(200, {'Content-Type': 'text/html'});
        response.write(data, 'utf-8');
        response.end();
    }
    );
})

server.get(new RegExp("^/(.*)(?:.jpg)?$"), function(request, response, match) {
    var output = match.indexOf('.jpg') >= 0 ? '/imgs/'+match : '/imgs/'+match+'.jpg';

    fs.readFile(__dirname+output, function (err, data) {
        if (err) {
            response.writeHead(404);
            response.end('Ups, we don\'t have image for that status code yet.');
        }
        else {
            response.writeHead(200, {'Content-Type': 'image/jpeg', 'Cache-Control': 'max-age=3600, public' });
            response.end(data);
        }
    });
})

server.listen(process.env.PORT || 8080, '0.0.0.0');

var server = require('node-router').getServer()

server.get(/.*/, function(request, response){
    response.writeHead(301, { Location: 'http://http.cat' + request.url})
    response.end();
})

server.listen(process.env.PORT || 8080, '0.0.0.0');

Change server to redirect to new domain


"use strict";

require("source-map-support/register");

if (typeof window === "object") {
  // eslint-disable-next-line no-native-reassign
  global = window;
  mocha.setup("bdd");
}

global.chai = require("chai");

global.expect = global.chai.expect;

"use strict";

require("source-map-support/register");

if (typeof window === "object") {
  window.global = window;
  mocha.setup("bdd");
}

global.chai = require("chai");

global.expect = global.chai.expect;

Fix bug in strict mode test bundles


'use strict';

var CE = require('..');

describe('Test getReferenceList', function () {
    it('Check the json', function () {
        this.timeout(20000);
        this.retries(5);
        return CE.getReferenceList('https://googledocs.cheminfo.org/spreadsheets/d/15Kuc5MeOhvm4oeTMvEuP1rWdRFiVWosxXhYwAmuf3Uo/export?format=tsv').then(function(result) {
            result.length.should.be.equal(1199);
            result[0].em.should.be.equal(22.0782503207);
        });
    });
});

'use strict';

var CE = require('..');

describe('Test getReferenceList', function () {
    it('Check the existing json', function () {
        this.timeout(20000);
        this.retries(5);
        return CE.getReferenceList('https://googledocs.cheminfo.org/spreadsheets/d/15Kuc5MeOhvm4oeTMvEuP1rWdRFiVWosxXhYwAmuf3Uo/export?format=tsv').then(function(result) {
            result.length.should.be.equal(1199);
            result[0].em.should.be.equal(22.0782503207);
        });
    });

    it('Check the non existing json', function () {
        this.timeout(20000);
        this.retries(5);
        return CE.getReferenceList('https://googledocs.cheminfo.org/spreadsheets/d/15Kuc5MeOhvm4xxxVWosxXhYwAmuf3Uo/export?format=tsv').then(function(result) {
            console.log(result);
        }).catch(function(error) {
            error.response.status.should.equal(404);
        });
    });

});

Add testcase for file not found


/**
 * The function that will trigger the editor
 *
 * @param element : string|Object the dom element to trigger the editor
 * @param defaultTextarea : object with textarea default values
 */
function triggerEditor(element, defaultTextarea) {

  Vue.component('Multiselect', VueMultiselect.default);
  Vue.use(VueResource);

  new Vue({

    el: element,
    data: {
      fields: [],
      textarea: defaultTextarea,
      // default values
      configuration: {
        enableTextareaOutput: true
      }
    },

    methods: {

      /**
       * Update the fields
       *
       * @param fields
       */
      updateFields: function (fields) {
        this.$set(this, 'fields', fields);
      }
    }

  });
}

/**
 * The function that will trigger the editor
 *
 * @param element : string|Object the dom element to trigger the editor
 * @param defaultTextarea : object with textarea default values
 */
function triggerEditor(element, defaultTextarea) {

  Vue.component('Multiselect', VueMultiselect.default);
  Vue.use(VueResource);

  /*Vue.http.interceptors.push(function (request, next) {
    if (request.method.toLowerCase() === 'get') {
      var cache = sessionStorage.getItem('cache_' + request.url);
      if (cache) {
        console.log('Cache hit', request.url);
        next(request.respondWith(cache, { status: 200, statusText: 'Ok'} ));

        return;
      } else {
        console.log('Cache miss', request.url);
      }
    }

    next(function(response) {
      if (typeof(response.headers.map['Content-Type']) !== 'undefined') {
        if (response.status === 200 && request.method.toLowerCase() === 'get') {
          console.log('Cache save', request.url);
          sessionStorage.setItem('cache_' + request.url, JSON.stringify(response.body));
        }
      }

      request.respondWith(response.body, {
        status: response.status,
        statusText: response.statusText
      })
    });
  });*/

  new Vue({

    el: element,
    data: {
      fields: [],
      textarea: defaultTextarea,
      // default values
      configuration: {
        enableTextareaOutput: true
      }
    },

    methods: {

      /**
       * Update the fields
       *
       * @param fields
       */
      updateFields: function (fields) {
        this.$set(this, 'fields', fields);
      }
    }

  });
}

Add interceptor to cache requests (comment it as it's slower than normal)


'use strict';

var assume = require('../../lib/assume.js');

describe('Assume.js embodying chai.expect', function () {

    it('should not have altered expect() used in these tests - just to be sure', function () {

        var expectThrewException = false;
        try {
            expect(true).to.eql(false);
        } catch (e) {
            expectThrewException = true;
        }

        if (expectThrewException === false) {
            throw Error('Expected expect() to throw an exception.');
        }

    });

    it('should allow basic assertions', function () {

        expect(function () { assume(true).to.eql(true);  }).to.not.throw();
        expect(function () { assume(true).to.eql(false); }).to.not.throw();

    });

});

'use strict';

var assume = require('../../lib/assume.js');

describe('Assume.js embodying chai.expect', function () {

    it('should not have altered expect() used in these tests - just to be sure', function () {

        var expectThrewException = false;
        try {
            expect(true).to.eql(false);
        } catch (e) {
            expectThrewException = true;
        }

        if (expectThrewException === false) {
            throw Error('Expected expect() to throw an exception.');
        }

    });

    it('should allow basic assertions', function () {

        expect(function () { assume(true).to.eql(true);  }).to.not.throw();
        expect(function () { assume(true).to.eql(false); }).to.not.throw();

    });

    it('should allow the assertion in the readme', function () {

        var foo = 'bar';
        var tea = {
            flavors: ['brownie', 'apple', 'raspberry']
        };

        expect(function () { assume(foo).to.be.a('string');                          }).to.not.throw();
        expect(function () { assume(foo).to.equal('bar');                            }).to.not.throw();
        expect(function () { assume(foo).to.have.length(3);                          }).to.not.throw();
        expect(function () { assume(tea).to.have.property('flavors').with.length(3); }).to.not.throw();

    });

});

Test for example in readme


var express = require('express');

module.exports = (keystone) => {
	let router = express.Router();

	/* GET home page. */
	router.get('/', function(req, res) {
		res.render('index', {title: 'Exchange.js'});
	});

	router.get('/talks', (req, res) => {
		keystone.list('Talk').model.find()
			.sort('-presentedOn')
			.populate('speaker')
			.exec((err, talks) => {
				res.render('talks', {
					title: 'Talks | Exchange.js',
					talks: talks
				});
			});
	});

	router.get('/:page', function(req, res, next) {
		keystone.list('Page').model.findOne({
			state: 'published',
			slug: req.params.page
		}).exec(function(err, result) {
			if (!result) {
				return next();
			}
			res.render('page', {
				title: result.title,
				content: result.content.html
			});
		});
	});

	return router;
}

var express = require('express');

module.exports = (keystone) => {
	let router = express.Router();

	/* GET home page. */
	router.get('/', function(req, res) {
		res.render('index', {title: 'Exchange.js'});
	});

	router.get('/talks', (req, res) => {
		keystone.list('Talk').model.find()
			.sort('-presentedOn')
			.populate('speaker')
			.exec((err, talks) => {
				res.render('talks', {
					title: 'Talks | Exchange.js',
					talks: talks
				});
			});
	});

	router.get('/:page', function(req, res, next) {
		keystone.list('Page').model.findOne({
			state: 'published',
			slug: req.params.page
		}).exec(function(err, result) {
			if (!result) {
				return next();
			}
			res.render('page', {
				title: result.title,
				content: result.content.html
			});
		});
	});

	// REDIRECT TO DEMO NIGHT VOTE FORM
	// REMOVE AFTER MAY 4TH 2017
	router.get('/vote', function(req, res) {
		res.redirect('https://docs.google.com/forms/d/e/1FAIpQLScCJjxmCA8Zg4ONi0UzV32d59-j1w0cHKgQK4iDMdE9EJZdvQ/viewform?usp=sf_link');
	});

	return router;
}

Add a quick url for voting for demo winners


/*
 * GET home page.
 */

exports.index = function(req, res){
  res.render('index', { title: 'IndieWebCamp IRC Atom Feed' });
};

exports.atom = function(req, res){
  res.render('atom');
};

exports.htmltest =function(req,res) {
  res.render('htmltest',  { title: 'HTML output test' });
};

/*
 * GET home page.
 */

exports.index = function(req, res){
  res.render('index', { title: 'IndieWebCamp IRC Atom Feed' });
};

exports.atom = function(req, res){
  res.contentType('application/atom+xml');
  res.render('atom');
};

exports.htmltest =function(req,res) {
  res.render('htmltest',  { title: 'HTML output test' });
};

Set content type to application/atom+xml


(function (logger, exec, Promise) {
    'use strict';
    module.exports = {
        getCommitId: function (commitId) {
            return new Promise(function (resolve, reject) {
                if (commitId) {
                    logger.debug('Provided Commit Id: ' + commitId);
                    return resolve(commitId);
                }

                var gitCommit = process.env.CODACY_GIT_COMMIT ||
                    process.env.TRAVIS_COMMIT ||
                    process.env.DRONE_COMMIT ||
                    process.env.GIT_COMMIT ||
                    process.env.CIRCLE_SHA1 ||
                    process.env.CI_COMMIT_ID ||
                    process.env.WERCKER_GIT_COMMIT ||
                    process.env.BUILDKITE_COMMIT;

                if (gitCommit) {
                    logger.debug('Received Commit Id: ' + gitCommit);
                    return resolve(gitCommit);
                }

                exec('git rev-parse HEAD', function (err, commitId) {
                    if (err) {
                        return reject(err);
                    }
                    commitId = commitId.trim();
                    logger.debug('Got Commit Id: ' + commitId);
                    resolve(commitId);
                });
            });
        }
    };
}(require('./logger')(), require('child_process').exec, require('bluebird')));

(function (logger, exec, Promise) {
    'use strict';
    module.exports = {
        getCommitId: function (commitId) {
            return new Promise(function (resolve, reject) {
                if (commitId) {
                    logger.debug('Provided Commit Id: ' + commitId);
                    return resolve(commitId);
                }

                var gitCommit = process.env.CODACY_GIT_COMMIT ||
                    process.env.TRAVIS_COMMIT ||
                    process.env.DRONE_COMMIT ||
                    process.env.GIT_COMMIT ||
                    process.env.CIRCLE_SHA1 ||
                    process.env.CI_COMMIT_ID ||
                    process.env.WERCKER_GIT_COMMIT ||
                    process.env.BUILDKITE_COMMIT ||
                    process.env.CI_COMMIT_SHA;

                if (gitCommit) {
                    logger.debug('Received Commit Id: ' + gitCommit);
                    return resolve(gitCommit);
                }

                exec('git rev-parse HEAD', function (err, commitId) {
                    if (err) {
                        return reject(err);
                    }
                    commitId = commitId.trim();
                    logger.debug('Got Commit Id: ' + commitId);
                    resolve(commitId);
                });
            });
        }
    };
}(require('./logger')(), require('child_process').exec, require('bluebird')));

Add GitLab CI commit env variable


import {utilFetchMocks} from 'tocco-util/dev'

import {createUsers} from './recordFactory'

const allRecords = createUsers(1000)

export default function setupFetchMock(fetchMock) {
  utilFetchMocks.sessionFetchMock(fetchMock)
  utilFetchMocks.textResourceFetchMock(fetchMock, require('./messages.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/form/.*'), require('./user_list.json'))

  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/.*/count$'), {'count': 1000})
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/.*'), (url, opts) => {
    console.log('fetchMock: called  fetch entites', url)
    const limit = parseInt(getParameterByName('_limit', url))
    const offset = parseInt(getParameterByName('_offset', url))

    return wrapResponse(allRecords.slice(offset, offset + limit))
  })

  fetchMock.spy()
}

const wrapResponse = records => ({
  metaData: {
    modelName: 'User',
    label: 'Person'
  },
  data: records
})

const getParameterByName = (name, url) => {
  name = name.replace(/[[\]]/g, '\\$&')
  const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
  const results = regex.exec(url)
  if (!results) return null
  if (!results[2]) return ''
  return decodeURIComponent(results[2].replace(/\+/g, ' '))
}

import {utilFetchMocks} from 'tocco-util/dev'

import {createUsers} from './recordFactory'

const allRecords = createUsers(1000)

export default function setupFetchMock(fetchMock) {
  utilFetchMocks.sessionFetchMock(fetchMock)
  utilFetchMocks.textResourceFetchMock(fetchMock, require('./messages.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/.*'), require('./user_list.json'))

  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/.*/count$'), {'count': 1000})
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/.*'), (url, opts) => {
    console.log('fetchMock: called  fetch entites', url)
    const limit = parseInt(getParameterByName('_limit', url))
    const offset = parseInt(getParameterByName('_offset', url))

    return wrapResponse(allRecords.slice(offset, offset + limit))
  })

  fetchMock.spy()
}

const wrapResponse = records => ({
  metaData: {
    modelName: 'User',
    label: 'Person'
  },
  data: records
})

const getParameterByName = (name, url) => {
  name = name.replace(/[[\]]/g, '\\$&')
  const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
  const results = regex.exec(url)
  if (!results) return null
  if (!results[2]) return ''
  return decodeURIComponent(results[2].replace(/\+/g, ' '))
}

Fix URL for forms fetch mock


/*
 *  (c) Daniel Arroyo. 3DaGoGo, Inc. (daniel@astroprint.com)
 *
 *  Distributed under the GNU Affero General Public License http://www.gnu.org/licenses/agpl.html
 */

 var PrinterProfile = Backbone.Model.extend({
 	url: API_BASEURL + "printer-profile",
	defaults: {
		'id': 'profile',
		'extruder_count': 2,
		'max_nozzle_temp': 280,
		'max_bed_temp': 140,
		'heated_bed': true,
		'cancel_gcode': null,
		'invert_z': false,
		// below two properties have been added for the extrusion process
		'extrusion_amount': 5,
		'extrusion_speed': 2
	}
});

/*
 *  (c) Daniel Arroyo. 3DaGoGo, Inc. (daniel@astroprint.com)
 *
 *  Distributed under the GNU Affero General Public License http://www.gnu.org/licenses/agpl.html
 */

 var PrinterProfile = Backbone.Model.extend({
	url: API_BASEURL + "printer-profile",
	defaults: {
		'id': 'profile',
		'extruder_count': 2,
		'max_nozzle_temp': 280,
		'max_bed_temp': 140,
		'heated_bed': true,
		'cancel_gcode': null,
		'invert_z': false,
		// below two properties have been added for the extrusion process
		'extrusion_amount': 5,
		'extrusion_speed': 2,

		/*
		* The nozzle and bed temperature's default values are set
		* These values are corresponds to the material 'PLA'
		*/
		'nozzle1Temp': 215,
		'nozzle2Temp': 215,
		'bedTemp': 72
	},
});

Add new default temperature attributes for extruder1, extruder2 and bed


/**
 * @ngdoc function
 * @name belajarOauth2ImplicitClientApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the belajarOauth2ImplicitClientApp
 */

(function() {
  'use strict';

  angular.module('belajarOauth2ImplicitClientApp')
    .controller('LoginCtrl', LoginCtrl);
  LoginCtrl.$inject = ['$location', '$window'];

  function LoginCtrl($location, $window) {
    var login = this;

    login.oauth2Url = 'http://localhost:8002/oauth/authorize?client_id=jsclient&response_type=token&scope=write';

    function loginUser() {
      $window.location.href = login.oauth2Url;
    }

    function checkLogin() {
      if ($window.sessionStorage.getItem('token')) {
        return;
      }

      loginUser();
    }

    checkLogin();

  }

})();

/**
 * @ngdoc function
 * @name belajarOauth2ImplicitClientApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the belajarOauth2ImplicitClientApp
 */

(function() {
  'use strict';

  angular.module('belajarOauth2ImplicitClientApp')
    .controller('LoginCtrl', LoginCtrl);
  LoginCtrl.$inject = ['$location', '$window'];

  function LoginCtrl($location, $window) {
    var login = this;

    login.oauth2Url = 'http://localhost:8002/oauth/authorize?client_id=jsclient&response_type=token&scope=write';

    function loginUser() {
      //redirect ke page login authorization
      $window.location.href = login.oauth2Url;
    }

    function getToken() {
      login.hashToken = $location.hash('');

      console.log(login.hashToken.$$path);

      //cek apa di url terdapat token
      if (!login.hashToken.$$path) {
        return;
      }

      login.pathUrl = login.hashToken.$$path.split('&')[0].replace('/', '');
      console.log(login.pathUrl);

      if (login.pathUrl.split('=')[0] === 'access_token') {
        console.log(login.pathUrl.split('=')[1]);

        $window.sessionStorage.setItem('token', login.pathUrl.split('=')[1]);
      }

    }

    function checkLogin() {

      //cek token di session storage dulu
      if ($window.sessionStorage.getItem('token')) {
        console.log('token ada');

        //redirect ke home page
        $window.location.href = 'http://localhost:8000/index#/';

        return;
      }

      //jika token di session storage masih kosong, cek url apakah terdapat access token
      getToken();

      //jika tidak ada token di session storage dan di url lakukan redirect ke page login authorization server
      loginUser();
    }

    //ketika statrup aplikasi lakukan pengecekan token user
    checkLogin();

  }

})();

Update Config for login user


var baseUrl = 'http://127.0.0.1:3000/';

// An example configuration file.
exports.config = {
  // Do not start a Selenium Standalone sever - only run this using chrome.
  //  chromeOnly: true,
  //  chromeDriver: './node_modules/protractor/selenium/chromedriver',
  seleniumAddress: 'http://0.0.0.0:4444/wd/hub',
  baseUrl: baseUrl,

  // Capabilities to be passed to the webdriver instance.
  capabilities: { 'browserName': 'chrome' },

  // Spec patterns are relative to the current working directly when
  // protractor is called.
  specs: ['*spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000
  }
};

"use strict";

var baseUrl = 'http://127.0.0.1:3000';
var mockUsers = require('../controllers/user-mock-store');

// An example configuration file.
exports.config = {
  // Do not start a Selenium Standalone sever - only run this using chrome.
  //  chromeOnly: true,
  //  chromeDriver: './node_modules/protractor/selenium/chromedriver',
  seleniumAddress: 'http://0.0.0.0:4444/wd/hub',
  baseUrl: baseUrl,

  // Capabilities to be passed to the webdriver instance.
  capabilities: { 'browserName': 'chrome' },

  // Spec patterns are relative to the current working directly when
  // protractor is called.
  specs: ['*spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000
  },

  onPrepare: function() {

    var loginUser = mockUsers[0];
    browser.driver.get(baseUrl + '/login');

    browser.driver.findElement(by.id('email')).sendKeys(loginUser.email);
    browser.driver.findElement(by.id('password')).sendKeys(loginUser.password);
    browser.driver.findElement(by.xpath("//node()[@type='submit']")).click();

    // Login takes some time, so wait until it's done.
    // For the test app's login, we know it's done when it redirects to
    // home page.
    browser.driver.wait(function() {
      return browser.driver.getCurrentUrl().then(function(url) {
        return new RegExp(baseUrl).test(url);
      });
    });
  }
};

Implement login before selenium test.


import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import window from 'ember-window-mock';
import { setupWindowMock } from 'ember-window-mock/test-support';
import timekeeper from 'timekeeper';

export default function (hooks) {
  setupMirage(hooks);
  setupWindowMock(hooks);

  // To have deterministic visual tests, the seed has to be constant
  hooks.beforeEach(function () {
    timekeeper.freeze(new Date('11/20/2017 12:00'));

    this.authenticateAs = user => {
      this.server.create('mirage-session', { user });
      window.localStorage.setItem('isLoggedIn', '1');
    };
  });

  hooks.afterEach(function () {
    timekeeper.reset();
  });
}

import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import window from 'ember-window-mock';
import { setupWindowMock } from 'ember-window-mock/test-support';
import timekeeper from 'timekeeper';

export default function (hooks) {
  setupMirage(hooks);
  setupWindowMock(hooks);

  // To have deterministic visual tests, the seed has to be constant
  hooks.beforeEach(function () {
    timekeeper.travel(new Date('2017-11-20T12:00:00'));

    this.authenticateAs = user => {
      this.server.create('mirage-session', { user });
      window.localStorage.setItem('isLoggedIn', '1');
    };
  });

  hooks.afterEach(function () {
    timekeeper.reset();
  });
}

Use time travel instead of time freezing


$(document).ready(function(){
    reblogSmoother();
    $(window).scroll(function(){
        reblogSmoother();
    });
});

function reblogSmoother(){
    var posts = $('.post_full, .post').has('blockquote blockquote')
    posts.html('[Smoothed by Polishr]');
}

$(document).ready(function(){
    reblogSmoother();
    $(window).scroll(function(){
        reblogSmoother();
    });
    $('.polishr-link').on('click', showPost);
});

var posts = {}

function reblogSmoother(){
    var index = 0;
    $('.post_full, .post').has('blockquote blockquote').each(function(){
        posts['' + index] = $(this).clone();
        $(this).html('
[Smoothed by Polishr] Show post
');
        $(this).addClass('polishr_post_' + index);
        index = index + 1;
    });
    $('.polishr-link').on('click', showPost);
}

function showPost(e){
    var id = e.target.id.split('_')[1];
    $('.polishr_post_' + id).html(posts[id].clone());
}

Add a show-link link to smoothed posts.


console.log('hello')
const css = require('../style/app.scss');

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

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: '',
      cardinality: 0
    };
  }

  cardinality(str) {
    return _.uniq(str.split('')).length;
  }

  textInput(e) {
    var input = this.refs.input.value.replace(/\s+/g, '');
    var cardinality = this.cardinality(input);
    this.setState({input, cardinality});
  }

  render() {
    return (

        <textarea ref="input" onKeyUp={this.textInput.bind(this)}/>
        Unique: {this.state.cardinality}

    )
  }
}

// main
ReactDOM.render(<App/>, document.getElementById('app'));

console.log('hello')
const css = require('../style/app.scss');

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

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: '',
      cardinality: 0,
      counts: {}
    };
  }

  counts(arr) {
    return _.countBy(arr, (x) => x)
  }

  cardinality(str) {
    return _.uniq(str.split('')).length;
  }

  textInput(e) {
    const input = this.refs.input.value.replace(/\s+/g, '');
    const cardinality = this.cardinality(input);
    const counts = this.counts(input.split(''));
    this.setState({input, cardinality, counts});
  }

  render() {
    const counts = _.map(
      this.state.counts, (v, k) =>
{k}: {v}

    );
    return (

        <textarea ref="input" onKeyUp={this.textInput.bind(this)}/>
        Unique: {this.state.cardinality}

          Counts:

{counts}

    )
  }
}

// main
ReactDOM.render(<App/>, document.getElementById('app'));

Add log of total counts


var sprintf = require('sprintf').sprintf;

var httpConstants = require('http/constants');

function returnError(res, code, msg) {
  var headers;
  code = code || 900;
  msg = msg || '';

  headers = {
    'Content-Length': msg.length,
    'Connection': 'close'
  };

  res.writeHead(code, headers);
  res.end(msg);
}

exports.returnError = returnError;

var sprintf = require('sprintf').sprintf;

var httpConstants = require('http/constants');

function returnError(res, code, msg) {
  var headers;
  code = code || 900;
  msg = msg || '';

  headers = {
    'Content-Length': msg.length,
    'Connection': 'close'
  };

  res.writeHead(code, headers);
  res.end(msg);
}

function extractParams(req, paramsObj) {
  var paramName, paramRules, paramValue;
  var paramValues = {};

  for (paramName in paramsObj) {
    if (paramsObj.hasOwnProperty(paramName)) {
      paramRules = paramsObj[paramName];
      paramValue = req.param(paramName, paramRules['default_value']);

      if (paramValue !== null) {
        if (paramRules['type'] === 'number') {
          paramValue = parseInt(paramValue, 10);
        }
      }

      paramValues[paramName] = paramValue;
    }
  }

  return paramValues;
}

exports.returnError = returnError;
exports.extractParams = extractParams;

Add method for extracting params from the request.


import 'normalize.css';
import 'HPCCloudStyle/global.mcss';

import React              from 'react';
import { render }         from 'react-dom';
import { Router }         from 'react-router';
import { Provider }       from 'react-redux';

import routes             from './config/routes';
import { store, history } from './redux';

// Setup application and pages
const container = document.querySelector('.react-container');

export function configure(config = { girderAPI: '/api/v1' }) {
  render(
    <Provider store={ store }>
      <Router history={ history } routes={ routes } />
    </Provider>, container);
}

import 'normalize.css';
import 'HPCCloudStyle/global.mcss';

import React              from 'react';
import { render }         from 'react-dom';
import { Router }         from 'react-router';
import { Provider }       from 'react-redux';

import routes                       from './config/routes';
import { store, history, dispatch } from './redux';
import * as ProjectActions          from './redux/actions/projects';

// Setup application and pages
const container = document.querySelector('.react-container');

export function configure(config = { girderAPI: '/api/v1' }) {
  render(
    <Provider store={ store }>
      <Router history={ history } routes={ routes } />
    </Provider>, container);
}

if (history) {
  history.listen(location => {
    var path = location.pathname.split('/');
    const id = path.pop();
    const type = path.pop();
    if (type === 'Simulation') {
      console.log('update active sim', id);
      dispatch(ProjectActions.setActiveSimulation(id));
    }
    if (type === 'Project') {
      console.log('update active proj', id);
      dispatch(ProjectActions.setActiveProject(id));
    }
  });
}

Monitor path to update active simulation and project via redux


var audio = document.getElementById("chris");

function pauseChris() {
	if (audio.currentTime >= 1283) {
		audio.pause();
		clearInterval(interval);
	}
}

function playChris() {
	audio.currentTime = 952;
	audio.play();
	var interval = setInterval(pauseChris, 1000);
}

function addChrisButton() {
	var div = document.getElementById("audioContainer");
	var button = document.createElement("BUTTON");
	button.setAttribute("type", "button");
	button.addEventListener("click", playChris);
	button.innerText = "Escuchar a Chris";
	div.insertBefore(button, audio);
}

addChrisButton();

var audio = document.getElementById("chris");

function pauseChris() {
	if (audio.currentTime >= 1283) {
		audio.pause();
		audio.currentTime = 952;
	}
}

function playChris() {
	audio.currentTime = 952;
	audio.play();
	var interval = setInterval(pauseChris, 1000);
}

function addChrisButton() {
	var div = document.getElementById("audioContainer");
	var button = document.createElement("BUTTON");
	button.setAttribute("type", "button");
	button.addEventListener("click", playChris);
	button.innerText = "Escuchar a Chris";
	div.insertBefore(button, audio);
}

addChrisButton();

Set current time to 952 after pause