import { set } from "@ember/object";
import Route from "@ember/routing/route";
import InfiniteScrollOffsetMixin from "ui/routes/-mixins/routes/infinite-scroll/offset";
import FilterLanguagesMixin from "ui/routes/-mixins/routes/filter-languages";
import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh";

export default Route.extend( InfiniteScrollOffsetMixin, FilterLanguagesMixin, RefreshRouteMixin, {
	itemSelector: ".stream-item-component",
	modelName: "twitchStream",
	modelPreload: "preview.mediumLatest",

	async model({ game }) {
		const model = await this._super({ game });

		return { game, model };
	},

	async fetchContent() {
		const { model } = await this.model({});

		return model;
	},

	setupController( controller, { game, model }, ...args ) {
		this._super( controller, model, ...args );
		set( controller, "game", game );
	}
});

import { get, set } from "@ember/object";
import Route from "@ember/routing/route";
import InfiniteScrollOffsetMixin from "ui/routes/-mixins/routes/infinite-scroll/offset";
import FilterLanguagesMixin from "ui/routes/-mixins/routes/filter-languages";
import RefreshRouteMixin from "ui/routes/-mixins/routes/refresh";

export default Route.extend( InfiniteScrollOffsetMixin, FilterLanguagesMixin, RefreshRouteMixin, {
	itemSelector: ".stream-item-component",
	modelName: "twitchStream",
	modelPreload: "preview.mediumLatest",

	async model({ game }) {
		const model = await this._super({ game });

		return { game, model };
	},

	async fetchContent() {
		const game = get( this.controller, "game" );
		const { model } = await this.model({ game });

		return model;
	},

	setupController( controller, { game, model }, ...args ) {
		this._super( controller, model, ...args );
		set( controller, "game", game );
	}
});

Fix fetchContent game parameter in GamesGameRoute


IDEToolbarType = {
    parent: Gtk.Toolbar.type,
    name: "IDEToolbar",
    class_init: function(klass, prototype)
    {

    },
    instance_init: function(klass)
    {
        this.new_button = actions.get_action("new").create_tool_item();
        this.open_button = actions.get_action("open").create_tool_item();
        this.save_button = actions.get_action("save").create_tool_item();
        this.undo_button = actions.get_action("undo").create_tool_item();
        this.redo_button = actions.get_action("redo").create_tool_item();
        this.execute_button = actions.get_action("execute").create_tool_item();

        this.insert(this.new_button, -1);
        this.insert(this.open_button, -1);
        this.insert(this.save_button, -1);
        this.insert(new Gtk.SeparatorToolItem(), -1);
        this.insert(this.undo_button, -1);
        this.insert(this.redo_button, -1);
        this.insert(new Gtk.SeparatorToolItem(), -1);
        this.insert(this.execute_button, -1);

        this.show_all();
    }};

IDEToolbar = new GType(IDEToolbarType);

IDEToolbarType = {
    parent: Gtk.Toolbar.type,
    name: "IDEToolbar",
    instance_init: function(klass)
    {
        this.new_button = actions.get_action("new").create_tool_item();
        this.open_button = actions.get_action("open").create_tool_item();
        this.save_button = actions.get_action("save").create_tool_item();
        this.undo_button = actions.get_action("undo").create_tool_item();
        this.redo_button = actions.get_action("redo").create_tool_item();
        this.execute_button = actions.get_action("execute").create_tool_item();

        this.insert(this.new_button, -1);
        this.insert(this.open_button, -1);
        this.insert(this.save_button, -1);
        this.insert(new Gtk.SeparatorToolItem(), -1);
        this.insert(this.undo_button, -1);
        this.insert(this.redo_button, -1);
        this.insert(new Gtk.SeparatorToolItem(), -1);
        this.insert(this.execute_button, -1);

        this.show_all();
    }};

IDEToolbar = new GType(IDEToolbarType);

Remove some dead code in examples.


import React, { Component } from "react";
import ReactDOM from "react-dom";

export default class ResultItem extends Component {
  componentDidUpdate() {
    if (this.props.selected) {
      ReactDOM.findDOMNode(this).scrollIntoView(false);
    }
  }
  render() {
    const { result, onClick, selected } = this.props;
    return (

 onClick(result)} className={selected ? 'selected' : ''}>

            {result.name}

            {result.author}

    );
  }
}

import React, { Component } from "react";
import ReactDOM from "react-dom";

export default class ResultItem extends Component {
  componentDidUpdate() {
    if (this.props.selected) {
      const node = ReactDOM.findDOMNode(this)
      if (node.scrollIntoViewIfNeeded) {
        node.scrollIntoViewIfNeeded(false)
      } else {
        node.scrollIntoView();
      }
    }
  }
  render() {
    const { result, onClick, selected } = this.props;
    return (

 onClick(result)} className={selected ? 'selected' : ''}>

            {result.name}

            {result.author}

    );
  }
}

Use beautiful scrolling if available


import { connect } from 'react-redux';
import shareIcon from 'assets/icons/share.svg';
import facebookIcon from 'assets/icons/facebook.svg';
import twitterIcon from 'assets/icons/twitter.svg';
import mailIcon from 'assets/icons/mail.svg';
import linkIcon from 'assets/icons/link.svg';
import copy from 'copy-to-clipboard';
import Component from './share-menu-component';

const mapStateToProps = (state, { path }) => {
  const url = location.origin + (path || location.pathname);
  const copyUrl = () => copy(url);
  const shareMenuOptions = [
    {
      label: 'Email',
      icon: mailIcon,
      link: `mailto:?subject=Climate%20Watch&body=${url}`
    },
    {
      label: 'Facebook',
      icon: facebookIcon,
      link: `https://www.facebook.com/sharer/sharer.php?u=${url}`
    },
    {
      label: 'Twitter',
      icon: twitterIcon,
      link: `https://twitter.com/intent/tweet?url=${url}`
    },
    {
      label: 'Copy link',
      icon: linkIcon,
      action: copyUrl
    }
  ];

  return {
    shareMenuOptions,
    shareIcon
  };
};

export default connect(mapStateToProps, null)(Component);

import { connect } from 'react-redux';
import shareIcon from 'assets/icons/share.svg';
import facebookIcon from 'assets/icons/facebook.svg';
import twitterIcon from 'assets/icons/twitter.svg';
import mailIcon from 'assets/icons/mail.svg';
import linkIcon from 'assets/icons/link.svg';
import copy from 'copy-to-clipboard';
import Component from './share-menu-component';

const mapStateToProps = (state, { path }) => {
  const url = location.origin + (path || location.pathname) + location.search;
  const copyUrl = () => copy(url);
  const shareMenuOptions = [
    {
      label: 'Email',
      icon: mailIcon,
      link: `mailto:?subject=Climate%20Watch&body=${url}`
    },
    {
      label: 'Facebook',
      icon: facebookIcon,
      link: `https://www.facebook.com/sharer/sharer.php?u=${url}`
    },
    {
      label: 'Twitter',
      icon: twitterIcon,
      link: `https://twitter.com/intent/tweet?url=${url}`
    },
    {
      label: 'Copy link',
      icon: linkIcon,
      action: copyUrl
    }
  ];

  return {
    shareMenuOptions,
    shareIcon
  };
};

export default connect(mapStateToProps, null)(Component);

Add params to share url


//= require diamond/thesis_menu

$(document).ready(function() {

  $(".link-export").click(function() {
    $(this).attr("href", $.clear_query_params($(this).attr("href"))+window.location.search);
  });

  $("button.select-all").click(function() {
    $("button.button-checkbox", "div.theses-list").trigger("checkbox-change-state");
  });

  $("button.destroy-all").lazy_form_confirmable_action({
    topic: 'confirmation_theses_delete',
    success_action: function(obj, key, val) {
      $("#thesis-"+key).remove();
    }
  });
  $("button.deny-selected").lazy_form_confirmable_action({
    topic: 'confirmation_theses_deny',
    success_action: function(obj, key, value) {
      $("#thesis-"+key).replaceWith($.parseHTML(value));
    }
  });
  $("button.accept-selected").lazy_form_confirmable_action({
    topic: 'confirmation_theses_accept',
    success_action: function(obj, key, value) {
      $("#thesis-"+key).replaceWith($.parseHTML(value));
    }
  });

});

$.widget( "core.per_page_paginator", $.core.loader, {

  before_state_changed: function(ctxt, e) {
    $("input[name='per_page']", ctxt).val($(e.currentTarget).html());
    $("input[name='page']", ctxt).val(1);
  }

});

Remove unused part of code


//= require jquery
//= require novnc-rails
//= require_tree ../locale
//= require gettext/all

$(function() {
  var host = window.location.hostname;
  var encrypt = window.location.protocol === 'https:';
  var port = encrypt ? 443 : 80;
  if (window.location.port) {
    port = window.location.port;
  }

  // noVNC requires an empty canvas item
  var canvas = document.createElement('canvas');
  $('#remote-console').append(canvas);

  var vnc = new RFB({
    target: canvas,
    encrypt: encrypt,
    true_color: true,
    local_cursor: true,
    shared: true,
    view_only: false,
    onUpdateState: function(_, state, _, msg) {
      if (['normal', 'loaded'].includes(state)) {
        $('#connection-status').removeClass('label-danger label-warning').addClass('label-success');
        $('#connection-status').text(__('Connected'));
      } else if (state === 'disconnected') {
        $('#connection-status').removeClass('label-success label-warning').addClass('label-danger');
        $('#connection-status').text(__('Disconnected'));
        console.error('VNC', msg);
      }
    },
  });

  $('#ctrlaltdel').click(vnc.sendCtrlAltDel);
  vnc.connect(host, port, $('#remote-console').attr('data-secret'), $('#remote-console').attr('data-url'));
});

//= require jquery
//= require novnc-rails
//= require_tree ../locale
//= require gettext/all

$(function() {
  var host = window.location.hostname;
  var encrypt = window.location.protocol === 'https:';
  var port = encrypt ? 443 : 80;
  if (window.location.port) {
    port = window.location.port;
  }

  // noVNC requires an empty canvas item
  var canvas = document.createElement('canvas');
  $('#remote-console').append(canvas);

  var vnc = new RFB({
    target: canvas,
    encrypt: encrypt,
    true_color: true,
    local_cursor: true,
    shared: true,
    view_only: false,
    onUpdateState: function(_, state, _, msg) {
      if (['normal', 'loaded'].indexOf(state) >= 0) {
        $('#connection-status').removeClass('label-danger label-warning').addClass('label-success');
        $('#connection-status').text(__('Connected'));
      } else if (state === 'disconnected') {
        $('#connection-status').removeClass('label-success label-warning').addClass('label-danger');
        $('#connection-status').text(__('Disconnected'));
        console.error('VNC', msg);
      }
    },
  });

  $('#ctrlaltdel').click(vnc.sendCtrlAltDel);
  vnc.connect(host, port, $('#remote-console').attr('data-secret'), $('#remote-console').attr('data-url'));
});

Replace function that IE11 does not support


import { inject as service } from '@ember/service';

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';

export default class CommentsList extends Component {
  @service account;
  @service ajax;

  @tracked addCommentText = '';

  @(task(function* () {
    let id = this.flightId;
    let text = this.addCommentText;
    let user = this.get('account.user');

    yield this.ajax.request(`/api/flights/${id}/comments`, { method: 'POST', json: { text } });

    this.addCommentText = '';
    this.comments.pushObject({ text, user });
  }).drop())
  addCommentTask;
}

import { inject as service } from '@ember/service';

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';

export default class CommentsList extends Component {
  @service account;
  @service ajax;

  @tracked addCommentText = '';

  @(task(function* () {
    let id = this.flightId;
    let text = this.addCommentText;
    let { user } = this.account;

    yield this.ajax.request(`/api/flights/${id}/comments`, { method: 'POST', json: { text } });

    this.addCommentText = '';
    this.comments.pushObject({ text, user });
  }).drop())
  addCommentTask;
}

Fix "this.get is not a function" issue


$j(document).ready(function(){
	G = new Game();

	$j("form#gamesetup").submit(function(e){
		e.preventDefault(); //prevent submit
		gameconfig = {
			nbrPlayer: $j('select[name="nbrplayer"]').val()-0,
			background_image : $j('select[name="background"]').val(),
			plasma_amount : $j('select[name="plasma"]').val()-0,
			timePool : $j('select[name="time_pool"]').val()*60,
			turnTimePool : $j('select[name="time_turn"]').val()-0,
			creaLimitNbr : $j('select[name="active_units"]').val()-0, //DP count as One
		};

		if( gameconfig.background_image == "random" ){
			var index = Math.floor(Math.random() * ($j('select[name="background"] option').length - 1) ) + 2;  // nth-child indices start at 1
			gameconfig.background_image = $j('select[name="background"] option:nth-child(' + index + ")").attr("value");
		}
		G.loadGame(gameconfig);
		return false; //prevent submit
	});
});

$j(document).ready(function(){
	G = new Game();

	$j("form#gamesetup").submit(function(e){
		e.preventDefault(); //prevent submit
		gameconfig = {
			nbrPlayer: $j('select[name="nbrplayer"]').val()-0,
			background_image : $j('select[name="background"]').val(),
			plasma_amount : $j('select[name="plasma"]').val()-0,
			timePool : $j('select[name="time_pool"]').val()*60,
			turnTimePool : $j('select[name="time_turn"]').val()-0,
			creaLimitNbr : $j('select[name="active_units"]').val()+1, //DP count as One
		};

		if( gameconfig.background_image == "random" ){
			var index = Math.floor(Math.random() * ($j('select[name="background"] option').length - 1) ) + 2;  // nth-child indices start at 1
			gameconfig.background_image = $j('select[name="background"] option:nth-child(' + index + ")").attr("value");
		}
		G.loadGame(gameconfig);
		return false; //prevent submit
	});
});

Change DP count in creature cap limit


Package.describe({
  summary: "Password support for accounts",
  version: "1.1.8-rc.0"
});

Package.onUse(function(api) {
  api.use('npm-bcrypt@=0.7.8_2');

  api.use([
    'accounts-base',
    'srp',
    'sha',
    'ejson',
    'ddp'
  ], ['client', 'server']);

  // Export Accounts (etc) to packages using this one.
  api.imply('accounts-base', ['client', 'server']);

  api.use('email', ['server']);
  api.use('random', ['server']);
  api.use('check');
  api.use('underscore');
  api.use('ecmascript');

  api.addFiles('email_templates.js', 'server');
  api.addFiles('password_server.js', 'server');
  api.addFiles('password_client.js', 'client');
});

Package.onTest(function(api) {
  api.use(['accounts-password', 'tinytest', 'test-helpers', 'tracker',
           'accounts-base', 'random', 'email', 'underscore', 'check',
           'ddp', 'ecmascript']);
  api.addFiles('password_tests_setup.js', 'server');
  api.addFiles('password_tests.js', ['client', 'server']);
  api.addFiles('email_tests_setup.js', 'server');
  api.addFiles('email_tests.js', 'client');
});

Package.describe({
  summary: "Password support for accounts",
  version: "1.1.8-rc.0"
});

Package.onUse(function(api) {
  api.use('npm-bcrypt@0.8.5');

  api.use([
    'accounts-base',
    'srp',
    'sha',
    'ejson',
    'ddp'
  ], ['client', 'server']);

  // Export Accounts (etc) to packages using this one.
  api.imply('accounts-base', ['client', 'server']);

  api.use('email', ['server']);
  api.use('random', ['server']);
  api.use('check');
  api.use('underscore');
  api.use('ecmascript');

  api.addFiles('email_templates.js', 'server');
  api.addFiles('password_server.js', 'server');
  api.addFiles('password_client.js', 'client');
});

Package.onTest(function(api) {
  api.use(['accounts-password', 'tinytest', 'test-helpers', 'tracker',
           'accounts-base', 'random', 'email', 'underscore', 'check',
           'ddp', 'ecmascript']);
  api.addFiles('password_tests_setup.js', 'server');
  api.addFiles('password_tests.js', ['client', 'server']);
  api.addFiles('email_tests_setup.js', 'server');
  api.addFiles('email_tests.js', 'client');
});

Make accounts-password depend on the newest version of npm-bcrypt.


const mlModelPath = chrome.runtime.getURL('assets/model/model.json');
const tokenizerPath = chrome.runtime.getURL('assets/tokenizer.json');

/** The entry point of the Chrome Extension. */
async function main() {
  // Load tokenizer dictionary
  const response = await fetch(tokenizerPath);
  const tokenizerObj = await response.json();
  const tokenizer = new Map(Object.entries(tokenizerObj));

  // Attempt to load ML model
  const model = await tf.loadLayersModel(mlModelPath);

  const labeller = new CalorieLabeller(tokenizer, model);
}

main();

const mlModelPath = chrome.runtime.getURL('assets/model/model.json');
const tokenizerPath = chrome.runtime.getURL('assets/tokenizer.json');
const dishNameSelector = '.menuItem-name';

/** The entry point of the Chrome Extension. */
async function main() {
  // Load tokenizer dictionary
  const response = await fetch(tokenizerPath);
  const tokenizerObj = await response.json();
  const tokenizer = new Map(Object.entries(tokenizerObj));

  // Attempt to load ML model
  const model = await tf.loadLayersModel(mlModelPath);
  const labeller = new CalorieLabeller(tokenizer, model);

  // Periodically check page to see if it has fully loaded.
  // Modern web pages will often "load" in the technical sense, but often
  // display a loading animation until dishes are actually populated.
  const stateCheck = setInterval(() => {
    if (document.querySelectorAll(dishNameSelector).length > 0) {
      clearInterval(stateCheck);
      for (const dishNameElem of document.querySelectorAll(dishNameSelector)) {
        labelDish(dishNameElem, labeller);
      }
    }
  }, 100);
}

/**
 * Label a single dish as low, average, or high-calorie. This includes
 * processing in the ML model, creating the label, and adding it to the DOM.
 *
 * The calorie label element will be added as a sibling to `dishNameElem` in the
 * DOM, coming directly after it.
 * @param {Element} dishNameElem DOM element that contains the dish name
 * @param {CalorieLabeller} labeller Determines what labels to give dishes
 */
async function labelDish(dishNameElem, labeller) {
  const dishName = dishNameElem.innerHTML;
  const calorieLabel = labeller.label(dishName);

  const calorieLabelElem = document.createElement('p');
  calorieLabelElem.appendChild(document.createTextNode(calorieLabel));
  dishNameElem.parentElement.appendChild(calorieLabelElem);
}

main();

Add labelling for dishes on grubhub


import React, { PropTypes } from "react"

const GitHubEditLink = ({ baseUrl, fileName, ...props }) => {
  const url = baseUrl + fileName

  return (
    <section {...props}>
      { "Bài viết sai chính tả? Có điểm chưa rõ ràng?" }
      { '  ' }
      <a href={ url } target="_blank">
        { "Sửa bài viết trên Github" }
      </a>
    </section>
  )
}

GitHubEditLink.propTypes = {
  baseUrl: PropTypes.string.isRequired,
  fileName: PropTypes.string.isRequired,
}

export default GitHubEditLink

import React, { PropTypes } from "react"

const GitHubEditLink = ({ baseUrl, fileName, ...props }) => {
  const url = baseUrl + fileName

  return (
    <section {...props}>
      { "Spotted typos or incorrect information?" }
      { '  ' }
      <a href={ url } target="_blank">
        { "Send me a PR on Github" }
      </a>
    </section>
  )
}

GitHubEditLink.propTypes = {
  baseUrl: PropTypes.string.isRequired,
  fileName: PropTypes.string.isRequired,
}

export default GitHubEditLink

Change GIthub PR to English


/* global showdown */
import Ember from 'ember';
import hbs from 'htmlbars-inline-precompile';

const { computed, get, Handlebars } = Ember;

const ShowdownComponent = Ember.Component.extend({
  layout: hbs`{{html}}`,
  markdown: '',

  extensions: computed(function() {
    return [];
  }),

  defaultOptionKeys: computed(function() {
    return Object.keys(showdown.getDefaultOptions());
  }).readOnly(),

  html: computed('markdown', function() {
    let showdownOptions = this.getProperties(get(this, 'defaultOptionKeys'));

    for (let option in showdownOptions) {
      if (showdownOptions.hasOwnProperty(option)) {
        this.converter.setOption(option, showdownOptions[option]);
      }
    }

    return new Handlebars.SafeString(this.converter.makeHtml(get(this, 'markdown')));
  }).readOnly(),

  didReceiveAttrs() {
    this._super(...arguments);

    let extensions = get(this, 'extensions');

    if (typeof extensions === 'string') {
      extensions = extensions.split(' ');
    }

    this.converter = new showdown.Converter({ extensions });
  }
});

ShowdownComponent.reopenClass({
  positionalParams: ['markdown']
});

export default ShowdownComponent;

/* global showdown */
import Ember from 'ember';
import hbs from 'htmlbars-inline-precompile';

const { computed, get, Handlebars } = Ember;

const ShowdownComponent = Ember.Component.extend({
  layout: hbs`{{html}}`,
  markdown: '',

  extensions: computed(function() {
    return [];
  }),

  defaultOptionKeys: computed(function() {
    return Object.keys(showdown.getDefaultOptions());
  }).readOnly(),

  html: computed('markdown', function() {
    let showdownOptions = this.getProperties(get(this, 'defaultOptionKeys'));

    for (let option in showdownOptions) {
      if (showdownOptions.hasOwnProperty(option)) {
        this.converter.setOption(option, showdownOptions[option]);
      }
    }

    return new Handlebars.SafeString(this.converter.makeHtml(get(this, 'markdown')));
  }).readOnly(),

  createConverter() {
    let extensions = get(this, 'extensions');

    if (typeof extensions === 'string') {
      extensions = extensions.split(' ');
    }

    this.converter = new showdown.Converter({ extensions });
  },

  didReceiveAttrs() {
    this._super(...arguments);

    this.createConverter();
  }
});

ShowdownComponent.reopenClass({
  positionalParams: ['markdown']
});

export default ShowdownComponent;

Move converter creation into it's own function for easier overriding


import Backbone from 'backbone';
import Geppetto from 'backbone.geppetto';

class BaseView extends Backbone.View {
	constructor(options) {
		super(options);

		if (!options.context || !(options.context instanceof Geppetto.Context)) {
			throw new Error('Supply the correct context instance.');
		}

		this.context = options.context;
		this.options = options;
	}

	render() {
		return this;
	}

	destroy() {
		this.context = undefined;
		this.options = undefined;
		delete(this.context);
		delete(this.options);
	}
}

export default BaseView;

import Backbone from 'backbone';
import Geppetto from 'backbone.geppetto';

/**
 * A generic view which inherits from the Backbone.View. This view is ment to
 * be used by all specific views in a project. It stores the references to all
 * given constructor options in the `.options` property. It also tests for and
 * stores the reference to the Backbone.Geppetto Context instance.
 *
 * @class Base-View
 * @example
 *		import BaseView from 'picnic/core/views/Base';
 *
 *		new BaseView({
 *			el: document.body,
 *			context: app.context
 *		}).render();
 */
class View extends Backbone.View {

	/**
	 * Creates an instance of this view.
	 *
	 * @constructor
	 * @param {object} options The settings for the view.
	 * @param {context} options.context The reference to the
	 *		backbone.geppetto context.
	 * @param {DOMElement|$Element} options.el the element reference for a
	 *		backbone.view.
	 */
	constructor(options) {
		super(options);

		if (!options.context || !(options.context instanceof Geppetto.Context)) {
			throw new Error('Supply the correct context instance.');
		}

		this.context = options.context;
		this.options = options;
	}

	/**
	 * This renders the content of this view and all models of the collection.
	 *
	 * @return {view} is the instance of this view.
	 */
	render() {
		return this;
	}

	/**
	 * Destroys this view.
	 */
	destroy() {
		this.context = undefined;
		this.options = undefined;
		delete(this.context);
		delete(this.options);
	}
}

export default View;

Add documentation for base view


Template.postSubmit.events({
    'submit form': function (event) {
        event.preventDefault();
        console.log('submitted');

        var post = {
            url: $(event.target).find('[name=url]').val(),
            title: $(event.target).find('[name=title]').val()
        }

        post._id = Posts.insert(post);
        Router.go('postPage', post);
    }
});

Template.postSubmit.events({
    'submit form': function (event) {
        event.preventDefault();
        console.log('submitted');

        var post = {
            url: $(event.target).find('[name=url]').val(),
            title: $(event.target).find('[name=title]').val()
        }

        Meteor.call('postInsert', post, function(error, result) {
            // display the error to the user and abort
            if (error) {
                return alert(error.reason):
            }
        }):

        Router.go('postPage', { _id: result._id });
    }
});

Use Meteor method to insert post.


var vow = require('vow');

var ApiMethod = require('../lib/api-method');
var ApiError = require('../lib/api-error');

/**
 * @typedef {Object} BatchApiMethod
 * @property {String} method Method name.
 * @property {Object} params Method params.
 *
 * @example
 * {
 *      method: 'hello',
 *      params: {name: 'Master'}
 * }
 */

module.exports = new ApiMethod('baby-loris-api-batch')
    .setDescription('Executes a set of methods')
    .setOption('hiddenOnDocPage', true)
    .addParam({
        // Methods are passed as an array of BatchApiMethod objects.
        name: 'methods',
        type: 'Array',
        description: 'Set of methods with a data',
        required: true
    })
    .setAction(function (params, api) {
        return vow.allResolved(params.methods.map(function (method) {
            return api.exec(method.method, method.params);
        })).then(function (response) {
            return response.map(function (promise) {
                var data = promise.valueOf();
                if (promise.isFulfilled()) {
                    return {
                        data: data
                    };
                } else {
                    return {
                        error: {
                            type: data.type || ApiError.INTERNAL_ERROR,
                            message: data.message
                        }
                    };
                }
            });
        });
    });

var vow = require('vow');

var ApiMethod = require('../lib/api-method');
var ApiError = require('../lib/api-error');

/**
 * @typedef {Object} BatchApiMethod
 * @property {String} method Method name.
 * @property {Object} params Method params.
 *
 * @example
 * {
 *      method: 'hello',
 *      params: {name: 'Master'}
 * }
 */

module.exports = new ApiMethod('baby-loris-api-batch')
    .setDescription('Executes a set of methods')
    .setOption('hiddenOnDocPage', true)
    .addParam({
        // Methods are passed as an array of BatchApiMethod objects.
        name: 'methods',
        type: 'Array',
        description: 'Set of methods with a data',
        required: true
    })
    .setAction(function (params, api) {
        return vow.allResolved(params.methods.map(function (method) {
            return api.exec(method.method, method.params);
        })).then(function (response) {
            return response.map(function (promise) {
                var data = promise.valueOf();

                if (promise.isFulfilled()) {
                    return {
                        data: data
                    };
                }

                return {
                    error: {
                        type: data.type || ApiError.INTERNAL_ERROR,
                        message: data.message
                    }
                };
            });
        });
    });

Remove else in batch method


module.exports = {
  verbose: true,
  collectCoverage: true,
  collectCoverageFrom: [
    'libs/**/*.{js,jsx}',
    'source/**/*.{js,jsx}',
  ],
  roots: [
    '<rootDir>/tests/',
  ],
  moduleNameMapper: {
    '^.+\\.(css|scss)$': 'identity-obj-proxy',
  },
  setupFiles: ['./tests/jestsetup.js'],
  snapshotSerializers: ['enzyme-to-json/serializer'],
};

module.exports = {
  verbose: true,
  collectCoverage: true,
  collectCoverageFrom: [
    'libs/**/*.{js,jsx}',
    'source/**/*.{js,jsx}',
    '!source/views/index.server.js',
  ],
  roots: [
    '<rootDir>/tests/',
  ],
  moduleNameMapper: {
    '^.+\\.(css|scss)$': 'identity-obj-proxy',
  },
  setupFiles: ['./tests/jestsetup.js'],
  snapshotSerializers: ['enzyme-to-json/serializer'],
};

Exclude ssr build from coverage


"use strict";

/*
  NOT a general purpose escaper! Only valid when *content* of a tag, not within an attribute.
 */
function escape(code) {
    return code
        .replace("&", "&", "g")
        .replace("<", "<", "g")
        .replace(">", ">", "g");
}

function lowlight(lang, lexer, code) {
    var ret = "";
    var lex = lexer.CeylonLexer(lexer.StringCharacterStream(code));
    var cur;
    while ((cur = lex.nextToken()) != null) {
        if (cur.type.string == "whitespace") {
            /*
               don’t put whitespace in a span –
               this way, styles can use CSS selectors
               based on the immediately previous node
               without worrying about whitespace
             */
            ret += cur.text;
        } else {
            ret += "";
            ret += escape(cur.text);
            ret += "";
        }
    }
    return ret;
}

Add supertypes of token types to span classes


function addslashes (str) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Ates Goral (http://magnetiq.com)
    // +   improved by: marrtins
    // +   improved by: Nate
    // +   improved by: Onno Marsman
    // +   input by: Denny Wardhana
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Oskar Larsson Hgfeldt (http://oskar-lh.name/)
    // *     example 1: addslashes("kevin's birthday");
    // *     returns 1: 'kevin\'s birthday'

    return (str+'').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
}

function addslashes (str) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Ates Goral (http://magnetiq.com)
    // +   improved by: marrtins
    // +   improved by: Nate
    // +   improved by: Onno Marsman
    // +   input by: Denny Wardhana
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Oskar Larsson Högfeldt (http://oskar-lh.name/)
    // *     example 1: addslashes("kevin's birthday");
    // *     returns 1: 'kevin\'s birthday'

    return (str+'').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
}

Switch to UTF-8 encoding of file to reflect contributor's name correctly


module.exports = function(config) {

  'use strict';

  require('./karma.conf')({

    set: function(base) {

      base.browsers = [
        'Firefox',
        'Opera',
        'PhantomJS',
        'Safari'
      ];

      config.set(base);

    }

  });

};

module.exports = function(config) {

  'use strict';

  require('./karma.conf')({

    set: function(base) {

      base.browsers = [
        'Firefox',
        'Chrome',
        'Opera',
        'PhantomJS',
        'Safari'
      ];

      config.set(base);

    }

  });

};

Add Chrome to local test runner.


'use strict';

/*
 * All app specific configuration
 */

const config = {};

config.gameLocation = {
  country : 'Sweden',
  lat : '59.751429',
  lon : '15.198645'
};

config.historyLines = 30;

config.chunkLength = 10;

config.userVerify = false;

module.exports = config;

'use strict';

/*
 * All app specific configuration
 */

const config = {};

config.gameLocation = {
  country : 'Sweden',
  lat : '59.751429',
  lon : '15.198645'
};

config.historyLines = 80;

config.chunkLength = 10;

config.userVerify = false;

module.exports = config;

Increase of default amount of messages sent in history


'use strict';

const testInfo = require('ember-cli-test-info');
const stringUtils = require('ember-cli-string-utils');

const useTestFrameworkDetector = require('../test-framework-detector');

module.exports = useTestFrameworkDetector({
  description: 'Generates an initializer unit test.',
  locals: function(options) {
    return {
      friendlyTestName: testInfo.name(options.entity.name, 'Unit', 'Initializer'),
      dasherizedModulePrefix: stringUtils.dasherize(options.project.config().modulePrefix)
    };
  }
});

'use strict';

const stringUtils = require('ember-cli-string-utils');

const useTestFrameworkDetector = require('../test-framework-detector');

module.exports = useTestFrameworkDetector({
  description: 'Generates an initializer unit test.',
  locals: function(options) {
    return {
      friendlyTestName: ['Unit', 'Initializer', options.entity.name].join(' | '),
      dasherizedModulePrefix: stringUtils.dasherize(options.project.config().modulePrefix)
    };
  }
});

Use `options.entity-name` for test description


define(['jquery', 'underscore', 'backbone'], function($, _, Backbone) {

  {{body}}

});

define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Backbone) {

  {{body}}

});

Fix AMD editors that must have backbone forms


/* global Chart */
import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'canvas',
  attributeBindings: ['width', 'height'],

  didInsertElement() {
    this._super(...arguments);
    let context = this.get('element');
    let data    = this.get('data');
    let type    = this.get('type');
    let options = this.get('options');

    let chart = new Chart(context, {
      type: type,
      data: data,
      options: options
    });
    this.set('chart', chart);
  },

  willDestroyElement() {
    this._super(...arguments);
    this.get('chart').destroy();
  },

  didUpdateAttrs() {
    this._super(...arguments);

    let chart   = this.get('chart');
    let data    = this.get('data');
    let options = this.get('options');
    let animate = this.get('animate');

		if (chart) {
			chart.config.data = data;
			chart.config.options = options;
			if (animate) {
				chart.update();
			} else {
				chart.update(0);
			}
		}
  }
});

/* global Chart */
import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'canvas',
  attributeBindings: ['width', 'height'],

  didInsertElement() {
    this._super(...arguments);
    let context = this.get('element');
    let data    = this.get('data');
    let type    = this.get('type');
    let options = this.get('options');

    let chart = new Chart(context, {
      type: type,
      data: data,
      options: options
    });
    this.set('chart', chart);
  },

  willDestroyElement() {
    this._super(...arguments);
    this.get('chart').destroy();
  },

  didUpdateAttrs() {
    this._super(...arguments);
    this.updateChart();
  },

  updateChart() {
    let chart   = this.get('chart');
    let data    = this.get('data');
    let options = this.get('options');
    let animate = this.get('animate');

		if (chart) {
			chart.config.data = data;
			chart.config.options = options;
			if (animate) {
				chart.update();
			} else {
				chart.update(0);
			}
		}
  }
});

Split out update logic into its own method


'use strict';

var rarity = require('rarity');

/**
 * Upload `event` (containing event data) onto AnyFetch.
 *
 *
 * @param {Object} event Event to upload, plus anyfetchClient
 * @param {Object} anyfetchClient Client for upload
 * @param {Function} cb Callback to call once events has been uploaded.
 */
module.exports = function(event, anyfetchClient, cb) {
  console.log("Uploading ", event.identifier);

  var eventDocument = {
    identifier: event.identifier,
    actions: {
      show: event.htmlLink
    },
    creation_date: event.created,
    modification_date: event.updated,
    metadata: {},
    document_type: 'event',
    user_access: [anyfetchClient.accessToken]
  };

  anyfetchClient.postDocument(eventDocument, rarity.slice(1, cb));
};

'use strict';

var rarity = require('rarity');

var getDateFromObject = function(obj) {
  if (!obj) {
    return undefined;
  }

  if (obj.datetime) {
    return new Date(obj.datetime);
  }
  else if (obj.date) {
    return new Date(obj.date);
  }
  else {
    return undefined;
  }
};

/**
 * Upload `event` (containing event data) onto AnyFetch.
 *
 *
 * @param {Object} event Event to upload, plus anyfetchClient
 * @param {Object} anyfetchClient Client for upload
 * @param {Function} cb Callback to call once events has been uploaded.
 */
module.exports = function(event, anyfetchClient, cb) {
  console.log("Uploading ", event.identifier);

  var eventDocument = {
    identifier: event.identifier,
    actions: {
      show: event.htmlLink
    },
    creation_date: event.created,
    modification_date: event.updated,
    metadata: {},
    document_type: 'event',
    user_access: [anyfetchClient.accessToken]
  };

  eventDocument.metadata.startDate = getDateFromObject(event.start);
  eventDocument.metadata.endDate = getDateFromObject(event.end);
  eventDocument.metadata.name = event.summary;
  eventDocument.metadata.description = event.description;
  eventDocument.metadata.location = event.location;

  if (event.attendee) {
    eventDocument.metadata.attendee = event.attendee.map(function(attendee) {
      return {
        name: attendee.displayName,
        mail: attendee.email
      };
    });
  }
  else {
    eventDocument.metadata.attendee = [];
  }

  anyfetchClient.postDocument(eventDocument, rarity.slice(1, cb));
};

Add a lots of metadata for events


import React from 'react'
import {render} from 'react-dom'
import {equal, ok} from 'assert'
import uniqueName from './uniqueName'

describe('uniqueName', () => {
  describe('no name specified', () => {
    it('has unique id', () => {
      const root = document.createElement('div')

      function Input ({name}) {
        return <input name={name} />
      }

      const UniquelyNamedInput = uniqueName(Input)

      render(
        <UniquelyNamedInput />,
        root
      )

      ok(
        root.children[0]
          .getAttribute('name')
          .match(/^Input-[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/)
      )
    })
  })

  describe('name specified', () => {
    it('has the name', () => {
      const root = document.createElement('div')

      function Input ({name}) {
        return <input name={name} />
      }

      const UniquelyNamedInput = uniqueName(Input)

      render(
        <UniquelyNamedInput name='actualName' />,
        root
      )

      equal(root.children[0].getAttribute('name'), 'actualName')
    })
  })
})

import React from 'react'
import {render} from 'react-dom'
import {equal, ok} from 'assert'
import uniqueName from './uniqueName'

describe('uniqueName', () => {
  describe('no name specified', () => {
    it('has unique id', () => {
      const root = document.createElement('div')

      function Input ({name}) {
        return <input name={name} />
      }

      const UniquelyNamedInput = uniqueName(Input)

      render(
        <div>
          <UniquelyNamedInput />
          <UniquelyNamedInput />
          <UniquelyNamedInput />
        </div>,
        root
      )

      const inputList = root.children[0].children

      ok(
        inputList[0]
          .getAttribute('name')
          .match(/^Input-[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/)
      )

      ok(
        inputList[0].getAttribute('name') !== inputList[1].getAttribute('name')
      )

      ok(
        inputList[1].getAttribute('name') !== inputList[2].getAttribute('name')
      )

      ok(
        inputList[0].getAttribute('name') !== inputList[2].getAttribute('name')
      )
    })
  })

  describe('name specified', () => {
    it('has the name', () => {
      const root = document.createElement('div')

      function Input ({name}) {
        return <input name={name} />
      }

      const UniquelyNamedInput = uniqueName(Input)

      render(
        <UniquelyNamedInput name='actualName' />,
        root
      )

      equal(root.children[0].getAttribute('name'), 'actualName')
    })
  })
})

Test uniqueness as well (weak test though)


"use strict";

var fs        = require("fs");
var path      = require("path");
var Sequelize = require("sequelize");
var env       = /*process.env.NODE_ENV || */"production";
var config    = require(path.join(__dirname, '..', 'config', 'config.json'))[env];
var sequelize = new Sequelize(config.database, config.username, config.password, config);
var db        = {};

fs
  .readdirSync(__dirname)
  .filter(function(file) {
    return (file.indexOf(".") !== 0) && (file !== "index.js");
  })
  .forEach(function(file) {
    var model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach(function(modelName) {
  if ("associate" in db[modelName]) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;
/* play.js
"use strict";

module.exports = function(sequelize, DataTypes) {
  var Play = sequelize.define("Play", {
  }, {
    comment : "Play table connect user A and room B so it means  A joined B.",
    classMethods: {
      associate: function(models) {
        Play.belongsTo(models.User, {foreignkey: 'username'});
        Play.belongsTo(models.Room, {foreignkey: 'roomid'});
      }
    }
  });

  return Play;
};
*/

"use strict";

var fs        = require("fs");
var path      = require("path");
var Sequelize = require("sequelize");
var env       = process.env.NODE_ENV || "production";
var config    = require(path.join(__dirname, '..', 'config', 'config.json'))[env];
var sequelize = new Sequelize(config.database, config.username, config.password, config);
var db        = {};

fs
  .readdirSync(__dirname)
  .filter(function(file) {
    return (file.indexOf(".") !== 0) && (file !== "index.js");
  })
  .forEach(function(file) {
    var model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach(function(modelName) {
  if ("associate" in db[modelName]) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;
/* play.js
"use strict";

module.exports = function(sequelize, DataTypes) {
  var Play = sequelize.define("Play", {
  }, {
    comment : "Play table connect user A and room B so it means  A joined B.",
    classMethods: {
      associate: function(models) {
        Play.belongsTo(models.User, {foreignkey: 'username'});
        Play.belongsTo(models.Room, {foreignkey: 'roomid'});
      }
    }
  });

  return Play;
};
*/

Remove comment because environment variable should be applied.


// Ensure fetch works from isolated world origin
fetch('http://localhost:1234')
fetch('https://localhost:1234')
fetch(`file://${__filename}`)

const {ipcRenderer, webFrame} = require('electron')

window.foo = 3

webFrame.executeJavaScript('window.preloadExecuteJavaScriptProperty = 1234;')

window.addEventListener('message', (event) => {
  ipcRenderer.send('isolated-world', {
    preloadContext: {
      preloadProperty: typeof window.foo,
      pageProperty: typeof window.hello,
      typeofRequire: typeof require,
      typeofProcess: typeof process,
      typeofArrayPush: typeof Array.prototype.push,
      typeofFunctionApply: typeof Function.prototype.apply
    },
    pageContext: event.data
  })
})

Add failing spec for fetch from isolated world


'use strict';

chrome.runtime.onInstalled.addListener(details => {
  console.log('previousVersion', details.previousVersion);
});

chrome.tabs.onUpdated.addListener(tabId => {
  chrome.pageAction.show(tabId);
});

console.log('\'Allo \'Allo! Event Page for Page Action');

'use strict';

chrome.runtime.onInstalled.addListener(details => {
  console.log('previousVersion', details.previousVersion);
  chrome.storage.sync.set({
    columnsToHide: '137, 1057, 1063',
    epicsToHide: '213682'
  });
});

chrome.tabs.onUpdated.addListener(tabId => {
  chrome.pageAction.show(tabId);
});

console.log('\'Allo \'Allo! Event Page for Page Action');

Set the columns and epics to hide on install


var test = require("tap").test
  , fs = require("fs")
  , path = require("path")
  , existsSync = fs.existsSync || path.existsSync
  , spawn = require("child_process").spawn
  , npm = require("../../")

test("not every pkg.name can be required", function (t) {
  t.plan(1)

  setup(function () {
    npm.install(".", function (err) {
      if (err) return t.fail(err)
      t.ok(existsSync(__dirname +
        "/false_name/node_modules/tap/node_modules/buffer-equal"))
    })
  })
})

function setup (cb) {
  process.chdir(__dirname + "/false_name")
  npm.load(function () {
    spawn("rm", [ "-rf", __dirname + "/false_name/node_modules" ])
      .on("exit", function () {
        fs.mkdirSync(__dirname + "/false_name/node_modules")
        cb()
      })
  })
}

var test = require("tap").test
  , fs = require("fs")
  , path = require("path")
  , existsSync = fs.existsSync || path.existsSync
  , spawn = require("child_process").spawn
  , npm = require("../../")
  , rimraf = require("rimraf")

test("not every pkg.name can be required", function (t) {
  t.plan(1)

  setup(function () {
    npm.install(".", function (err) {
      if (err) return t.fail(err)
      t.ok(existsSync(__dirname +
        "/false_name/node_modules/tap/node_modules/buffer-equal"))
    })
  })
})

function setup (cb) {
  process.chdir(__dirname + "/false_name")
  npm.load(function () {
    rimraf.sync(__dirname + "/false_name/node_modules")
    fs.mkdirSync(__dirname + "/false_name/node_modules")
    cb()
  })
}

Use rimraf instead of spawning rm -rf


define(['./node', './joinId', './imports'], function (
           node,     joinId,     imports) {

    return function (requestedFiles, nodes) {
        var is = imports(requestedFiles, nodes);

        var trees = [];
        requestedFiles.forEach(function (file) {
            var index = {};
            nodes.forEach(function (n) { index[joinId(n.getId())] = n; });

            var id = joinId(file.getId());

            var children = index[id].getNestedNodes().map(function (c) {
                return node(c, index);
            });

            trees.push({
                name : file.getFilename().asString(),
                meta : "file",
                imports : is[id],
                id : id,
                nodes : children
            });
        });

        return trees;
    };
});

define(['./node', './joinId', './imports'], function (
           node,     joinId,     imports) {

    return function (requestedFiles, nodes) {
        var is = imports(requestedFiles, nodes);

        var trees = [];
        requestedFiles.forEach(function (file) {
            var index = {};
            nodes.forEach(function (n) { index[joinId(n.getId())] = n; });

            var id = joinId(file.getId());

            var children = index[id].getNestedNodes().map(function (c) {
                return node(c, index);
            });

            trees.push({
                name : file.getFilename().toString(),
                meta : "file",
                imports : is[id],
                id : id,
                nodes : children
            });
        });

        return trees;
    };
});

Use toString instead of asString


import fs from "fs-extra";
import path from "path";
import inquirer from "inquirer";
import sha1 from "sha1";
import readFileSyncStrip from "../lib/readFileSyncStrip";
import logger from "../lib/logger";
import { warn } from "../lib/logsColorScheme";

function doUpdate(from, to) {
  logger.info("Updating .babelrc file...");
  fs.copySync(from, to);
}

export default function updateBabelConfig() {
  return new Promise(resolve => {

    const projectConfigPath = path.join(process.cwd(), ".babelrc");
    const latestConfigPath = path.join(__dirname, "../..", "new", ".babelrc");
    const projectSha = sha1(readFileSyncStrip(projectConfigPath));
    const previousSha = sha1(readFileSyncStrip(path.join(__dirname, "previous", ".babelrc")));
    const latestSha = sha1(readFileSyncStrip(latestConfigPath));

    if (projectSha === latestSha) {
      return resolve();
    }
    else if (projectSha !== previousSha) {
      const question = {
        type: "confirm",
        name: "confirm",
        message: `${warn("The format of .babelrc is out of date. Would you like to automatically update it?")}`
      };

      inquirer.prompt([question], function (answers) {
        if (!answers.confirm) {
          const latestConfig = fs.readFileSync(latestConfigPath);
          logger.info(`It is recommended that you update your .babelrc file. Here is an example file:\n${latestConfig}`);
          return resolve();
        }

        doUpdate(latestConfigPath, projectConfigPath);
        resolve();
      });
    }
  });
}

import fs from "fs-extra";
import path from "path";
import inquirer from "inquirer";
import sha1 from "sha1";
import readFileSyncStrip from "../lib/readFileSyncStrip";
import logger from "../lib/logger";
import { warn } from "../lib/logsColorScheme";

function doUpdate(from, to) {
  logger.info("Updating .babelrc file...");
  fs.copySync(from, to);
}

export default function updateBabelConfig() {
  return new Promise(resolve => {

    const projectConfigPath = path.join(process.cwd(), ".babelrc");
    const latestConfigPath = path.join(__dirname, "../..", "new", ".babelrc");
    const projectSha = sha1(readFileSyncStrip(projectConfigPath));
    const previousSha = sha1(readFileSyncStrip(path.join(__dirname, "previous", ".babelrc")));
    const latestSha = sha1(readFileSyncStrip(latestConfigPath));

    if (projectSha === latestSha) {
      return resolve();
    }
    else if (projectSha !== previousSha) {
      const question = {
        type: "confirm",
        name: "confirm",
        message: `${warn("The format of .babelrc is out of date. Would you like to automatically update it?")}`
      };

      inquirer.prompt([question], function (answers) {
        if (!answers.confirm) {
          const latestConfig = fs.readFileSync(latestConfigPath);
          logger.info(`It is recommended that you update your .babelrc file. Here is an example file:\n${latestConfig}`);
          return resolve();
        }

        doUpdate(latestConfigPath, projectConfigPath);
        return resolve();
      });
    }
    doUpdate(latestConfigPath, projectConfigPath);
    return resolve();
  });
}

Upgrade if the user's file matches the previous


// ==UserScript==
// @name           Modify URL @2ch
// @namespace      curipha
// @description    Modify texts starting with "ttp://" to anchor and redirect URIs to direct link
// @include        http://*.2ch.net/*
// @include        http://*.bbspink.com/*
// @version        0.1.2
// @grant          none
// @noframes
// ==/UserScript==

(function(){
  'use strict';

  var anchor  = document.getElementsByTagName('a');

  for (var a of anchor) {
    if (a.href.indexOf('http://jump.2ch.net/?') === 0) {
      a.href = decodeURIComponent(a.href.slice(21)); // 'http://jump.2ch.net/?'.length -> 21
    }
    else if (a.href.indexOf('http://pinktower.com/?') === 0) {
      a.href = decodeURIComponent('http://' + a.href.slice(22)); // 'http://pinktower.com/?'.length -> 22
    }
  }

  var res = document.getElementsByTagName('dd');
  if (res.length < 1) res = document.getElementsByClassName('message');

  var ttp = /([^h])(ttps?:\/\/[\x21\x23-\x3b\x3d\x3f-\x7E]+)/ig;

  for (var d of res) {
    d.innerHTML = d.innerHTML.replace(ttp, '$1$2');
  }
})();

// ==UserScript==
// @name           Modify URL @2ch
// @namespace      curipha
// @description    Modify texts starting with "ttp://" to anchor and redirect URIs to direct link
// @include        http://*.2ch.net/*
// @include        http://*.bbspink.com/*
// @version        0.1.2
// @grant          none
// @noframes
// ==/UserScript==

(function(){
  'use strict';

  var anchor  = document.getElementsByTagName('a');

  for (var a of anchor) {
    if (a.href.indexOf('http://jump.2ch.net/?') === 0) {
      a.href = decodeURIComponent(a.href.slice(21)); // 'http://jump.2ch.net/?'.length -> 21
    }
    else if (a.href.indexOf('http://pinktower.com/?') === 0) {
      a.href = decodeURIComponent('http://' + a.href.slice(22)); // 'http://pinktower.com/?'.length -> 22
    }
  }

  var res = document.getElementsByTagName('dd');
  if (res.length < 1) res = document.getElementsByClassName('message');

  var ttp = /([^h]|^)(ttps?:\/\/[\x21\x23-\x3b\x3d\x3f-\x7E]+)/ig;

  for (var d of res) {
    d.innerHTML = d.innerHTML.replace(ttp, '$1$2');
  }
})();

Convert 'ttp' string to link even if it appears at the first position of response


/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import { configure } from '@storybook/react';
import { setOptions } from '@storybook/addon-options';
import 'react-chromatic/storybook-addon';
import addHeadWarning from './head-warning';

addHeadWarning('Preview');

setOptions({
  hierarchySeparator: /\/|\./,
  hierarchyRootSeparator: /\|/,
});

function loadStories() {
  let req;
  req = require.context('../../lib/ui/src', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));

  req = require.context('../../lib/components/src', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));

  req = require.context('./stories', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import { configure } from '@storybook/react';
import { setOptions } from '@storybook/addon-options';
import 'react-chromatic/storybook-addon';
import addHeadWarning from './head-warning';

addHeadWarning('Preview');

setOptions({
  hierarchySeparator: /\/|\.|\\/,
  hierarchyRootSeparator: /\|/,
});

function loadStories() {
  let req;
  req = require.context('../../lib/ui/src', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));

  req = require.context('../../lib/components/src', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));

  req = require.context('./stories', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

FIX windows BS paths containing a slash in the freaking wrong direction, total BS


var metaRouter = require('../');
var DataHolder = require('raptor-async/DataHolder');

module.exports = function match(routes) {
    var matcher;
    var matcherDataHolder;

    if (typeof routes === 'string') {
        matcherDataHolder = new DataHolder();
        metaRouter.routesLoader.load(routes, function(err, routes) {
            if (err) {
                return matcherDataHolder.reject(err);
            }

            matcher = metaRouter.buildMatcher(routes);
            matcherDataHolder.resolve(matcher);
        });
    } else {
        matcher = metaRouter.buildMatcher(routes);
    }

    function go(matcher, req, res, next) {
        var match = matcher.match(req.method, req.path);
        if (match) {
            req.route = match;
        }

        next();
    }

    return function(req, res, next) {
        if (matcher) {
            go(matcher, req, res, next);
        } else {
            matcherDataHolder.done(function(err, matcher) {
                if (err) {
                    return next(err);
                }

                go(matcher, req, res, next);
            });
        }

    };
};

var metaRouter = require('../');
var DataHolder = require('raptor-async/DataHolder');
var nodePath = require('path');

module.exports = function match(routes) {
    var matcher;
    var matcherDataHolder;

    if (typeof routes === 'string') {
        routes = nodePath.resolve(process.cwd(), routes);

        matcherDataHolder = new DataHolder();
        metaRouter.routesLoader.load(routes, function(err, routes) {
            if (err) {
                return matcherDataHolder.reject(err);
            }

            matcher = metaRouter.buildMatcher(routes);
            matcherDataHolder.resolve(matcher);
        });
    } else {
        matcher = metaRouter.buildMatcher(routes);
    }

    function go(matcher, req, res, next) {
        var match = matcher.match(req.method, req.path);
        if (match) {
            req.route = match;
        }

        next();
    }

    return function(req, res, next) {
        if (matcher) {
            go(matcher, req, res, next);
        } else {
            matcherDataHolder.done(function(err, matcher) {
                if (err) {
                    return next(err);
                }

                go(matcher, req, res, next);
            });
        }

    };
};

Resolve all paths to CWD


var loadTodos = function() {
  $.ajax({
    url: "/graphql?query={todoList{id,text,done}}"
  }).done(function(data) {
    console.log(data);
    var dataParsed = JSON.parse(data);
    var todos = dataParsed.data.todoList;

    if (!todos.length) {
      $('.todo-list-container').append('
There are no tasks for you today
');
    }

    $.each(todos, function(i, v) {
      var doneHtml = '<input id="' + v.id + '" type="checkbox"' + (v.done ? ' checked="checked"' : '') + '>';
      var labelHtml = '' + doneHtml + v.text + '';
      var itemHtml = '
' + labelHtml + '
';

      $('.todo-list-container').append(itemHtml);
    });
  });
};

$(document).ready(function() {
  loadTodos();
});

var handleTodoList = function(object) {
  var todos = object;

  if (!todos.length) {
    $('.todo-list-container').append('
There are no tasks for you today
');
  }

  $.each(todos, function(i, v) {
    var doneHtml = '<input id="' + v.id + '" type="checkbox"' + (v.done ? ' checked="checked"' : '') + '>';
    var labelHtml = '' + doneHtml + v.text + '';
    var itemHtml = '
' + labelHtml + '
';

    $('.todo-list-container').append(itemHtml);
  });
};

var loadTodos = function() {
  $.ajax({
    url: "/graphql?query={todoList{id,text,done}}"
  }).done(function(data) {
    console.log(data);
    var dataParsed = JSON.parse(data);
    handleTodoList(dataParsed.data.todoList);
  });
};

var addTodo = function(todoText) {
  if (!todoText || todoText === "") {
    alert('Please specify a task');
    return;
  }

  $.ajax({
    url: '/graphql?query=mutation+_{createTodo(text:"' + todoText + '"){id,text,done}}'
  }).done(function(data) {
    console.log(data);
    var dataParsed = JSON.parse(data);
    var todoList = [dataParsed.data.createTodo];
    handleTodoList(todoList);
  });
};

$(document).ready(function() {
  $('.todo-add-form button').click(function(){
    addTodo($('.todo-add-form #task').val());
    $('.todo-add-form #task').val('');
  });

  loadTodos();
});

Add "Add task" functionality, use the mutation


Package.describe({
  summary: "Password support for accounts",
  version: "1.3.6"
});

Package.onUse(function(api) {
  api.use('npm-bcrypt', 'server');

  api.use([
    'accounts-base',
    'srp',
    'sha',
    'ejson',
    'ddp'
  ], ['client', 'server']);

  // Export Accounts (etc) to packages using this one.
  api.imply('accounts-base', ['client', 'server']);

  api.use('email', ['server']);
  api.use('random', ['server']);
  api.use('check');
  api.use('underscore');
  api.use('ecmascript');

  api.addFiles('email_templates.js', 'server');
  api.addFiles('password_server.js', 'server');
  api.addFiles('password_client.js', 'client');
});

Package.onTest(function(api) {
  api.use(['accounts-password', 'tinytest', 'test-helpers', 'tracker',
           'accounts-base', 'random', 'email', 'underscore', 'check',
           'ddp', 'ecmascript']);
  api.addFiles('password_tests_setup.js', 'server');
  api.addFiles('password_tests.js', ['client', 'server']);
  api.addFiles('email_tests_setup.js', 'server');
  api.addFiles('email_tests.js', 'client');
});

Package.describe({
  summary: "Password support for accounts",
  version: "1.3.7"
});

Package.onUse(function(api) {
  api.use('npm-bcrypt', 'server');

  api.use([
    'accounts-base',
    'srp',
    'sha',
    'ejson',
    'ddp'
  ], ['client', 'server']);

  // Export Accounts (etc) to packages using this one.
  api.imply('accounts-base', ['client', 'server']);

  api.use('email', ['server']);
  api.use('random', ['server']);
  api.use('check');
  api.use('underscore');
  api.use('ecmascript');

  api.addFiles('email_templates.js', 'server');
  api.addFiles('password_server.js', 'server');
  api.addFiles('password_client.js', 'client');
});

Package.onTest(function(api) {
  api.use(['accounts-password', 'tinytest', 'test-helpers', 'tracker',
           'accounts-base', 'random', 'email', 'underscore', 'check',
           'ddp', 'ecmascript']);
  api.addFiles('password_tests_setup.js', 'server');
  api.addFiles('password_tests.js', ['client', 'server']);
  api.addFiles('email_tests_setup.js', 'server');
  api.addFiles('email_tests.js', 'client');
});

Bump version of `accounts-password` in preparation for publishing.


const mountComponent = (Component, props = {}, el = null) =>
  new Component({
    propsData: props,
  }).$mount(el);

export const createComponentWithStore = (Component, store, propsData = {}) =>
  new Component({
    store,
    propsData,
  });

export const mountComponentWithStore = (Component, { el, props, store }) =>
  new Component({
    store,
    propsData: props || {},
  }).$mount(el);

export const mountComponentWithSlots = (Component, { props, slots }) => {
  const component = new Component({
    propsData: props || {},
  });

  component.$slots = slots;

  return component.$mount();
};

export default mountComponent;

import Vue from 'vue';

const mountComponent = (Component, props = {}, el = null) =>
  new Component({
    propsData: props,
  }).$mount(el);

export const createComponentWithStore = (Component, store, propsData = {}) =>
  new Component({
    store,
    propsData,
  });

export const mountComponentWithStore = (Component, { el, props, store }) =>
  new Component({
    store,
    propsData: props || {},
  }).$mount(el);

export const mountComponentWithSlots = (Component, { props, slots }) => {
  const component = new Component({
    propsData: props || {},
  });

  component.$slots = slots;

  return component.$mount();
};

/**
 * Mount a component with the given render method.
 *
 * This helps with inserting slots that need to be compiled.
 */
export const mountComponentWithRender = (render, el = null) =>
  mountComponent(Vue.extend({ render }), {}, el);

export default mountComponent;

Create 'mountComponentWithRender' for testing with slots


import coreUtils from '@opentripplanner/core-utils'
import { ClassicLegIcon } from '@opentripplanner/icons'
import React from 'react'

import ItinerarySummary from '../../narrative/default/itinerary-summary'

const { formatDuration, formatTime } = coreUtils.time

const TripSummary = ({ monitoredTrip }) => {
  const { itinerary } = monitoredTrip
  const { duration, endTime, startTime } = itinerary
  // TODO: use the modern itinerary summary built for trip comparison.
  return (
    <div
      className={`otp option default-itin active`}
      style={{borderTop: '0px', padding: '0px'}}>

        Itinerary{' '}
        {formatDuration(duration)}{' '}
        {formatTime(startTime)}—{formatTime(endTime)}
        <ItinerarySummary itinerary={itinerary} LegIcon={ClassicLegIcon} />

  )
}

export default TripSummary

import coreUtils from '@opentripplanner/core-utils'
import { ClassicLegIcon } from '@opentripplanner/icons'
import React from 'react'

import ItinerarySummary from '../../narrative/default/itinerary-summary'

const { formatDuration, formatTime } = coreUtils.time

const TripSummary = ({ monitoredTrip }) => {
  const { itinerary } = monitoredTrip
  const { duration, endTime, startTime } = itinerary
  // TODO: use the modern itinerary summary built for trip comparison.
  return (
    <div
      className={`otp option default-itin`}
      style={{borderTop: '0px', padding: '0px'}}>

        Itinerary{' '}
        {formatDuration(duration)}{' '}
        {formatTime(startTime)}—{formatTime(endTime)}
        <ItinerarySummary itinerary={itinerary} LegIcon={ClassicLegIcon} />

  )
}

export default TripSummary

Remove green bar outside of batch itinerary results.


import Controller from '@ember/controller';
import { get, set } from '@ember/object';
import WithFiltering from 'consul-ui/mixins/with-filtering';

export default Controller.extend(WithFiltering, {
  queryParams: {
    s: {
      as: 'filter',
      replace: true,
    },
  },
  setProperties: function() {
    this._super(...arguments);
    set(this, 'selectedTab', 'health-checks');
  },
  filter: function(item, { s = '' }) {
    return (
      get(item, 'Service')
        .toLowerCase()
        .indexOf(s.toLowerCase()) !== -1
    );
  },
  actions: {
    sortChecksByImportance: function(a, b) {
      const statusA = get(a, 'Status');
      const statusB = get(b, 'Status');
      switch (statusA) {
        case 'passing':
          // a = passing
          // unless b is also passing then a is less important
          return statusB === 'passing' ? 0 : 1;
        case 'critical':
          // a = critical
          // unless b is also critical then a is more important
          return statusB === 'critical' ? 0 : -1;
        case 'warning':
          // a = warning
          switch (statusB) {
            // b is passing so a is more important
            case 'passing':
              return -1;
            // b is critical so a is less important
            case 'critical':
              return 1;
            // a and b are both warning, therefore equal
            default:
              return 0;
          }
      }
      return 0;
    },
  },
});

import Controller from '@ember/controller';
import { get, set } from '@ember/object';
import WithFiltering from 'consul-ui/mixins/with-filtering';

export default Controller.extend(WithFiltering, {
  queryParams: {
    s: {
      as: 'filter',
      replace: true,
    },
  },
  setProperties: function() {
    this._super(...arguments);
    set(this, 'selectedTab', 'health-checks');
  },
  filter: function(item, { s = '' }) {
    const term = s.toLowerCase();
    return (
      get(item, 'Service')
        .toLowerCase()
        .indexOf(term) !== -1 ||
      get(item, 'Port')
        .toString()
        .toLowerCase()
        .indexOf(term) !== -1
    );
  },
  actions: {
    sortChecksByImportance: function(a, b) {
      const statusA = get(a, 'Status');
      const statusB = get(b, 'Status');
      switch (statusA) {
        case 'passing':
          // a = passing
          // unless b is also passing then a is less important
          return statusB === 'passing' ? 0 : 1;
        case 'critical':
          // a = critical
          // unless b is also critical then a is more important
          return statusB === 'critical' ? 0 : -1;
        case 'warning':
          // a = warning
          switch (statusB) {
            // b is passing so a is more important
            case 'passing':
              return -1;
            // b is critical so a is less important
            case 'critical':
              return 1;
            // a and b are both warning, therefore equal
            default:
              return 0;
          }
      }
      return 0;
    },
  },
});

Enable searching by port in the Node > [Service] listing


// ==UserScript==
// @name         Twitch Auto Theater
// @version      1.0.3
// @updateURL    https://raw.githubusercontent.com/domosapien/Twitch-Auto-Theater/master/twitch-auto-theater.js
// @downloadURL  https://raw.githubusercontent.com/domosapien/Twitch-Auto-Theater/master/twitch-auto-theater.js
// @match        www.twitch.tv/*
// @grant        none
// ==/UserScript==

/* jshint -W097 jquery:true */

'use strict';

var observer = new MutationObserver(function (mutations) {
	mutations.forEach(function (mutation) {
		if (!mutation.addedNodes) {
			return;
		}

		for (var i = 0; i < mutation.addedNodes.length; i++) {
			// do things to your newly added nodes here
			var $node = $(mutation.addedNodes[i]).find('button.player-button--theatre');
			if ($node.length) {
				$node.trigger('click');
				observer.disconnect();
				return;
			}
		}
	});
});

function startObserver() {
	observer.observe(document.body, {
		childList: true,
		subtree: true,
		attributes: false,
		characterData: false
	});
}

startObserver();

window.onpopstate = function (event) {
	startObserver();
};

// ==UserScript==
// @name         Twitch Auto Theater
// @version      1.0.4
// @updateURL    https://raw.githubusercontent.com/domosapien/Twitch-Auto-Theater/master/twitch-auto-theater.js
// @downloadURL  https://raw.githubusercontent.com/domosapien/Twitch-Auto-Theater/master/twitch-auto-theater.js
// @match        www.twitch.tv/*
// @grant        none
// ==/UserScript==

/* jshint -W097 jquery:true */

'use strict';

var observer = new MutationObserver(function (mutations) {
    mutations.some(function (mutation) {
        if (!mutation.addedNodes) {
            return false;
        }

        for (var i = 0; i < mutation.addedNodes.length; i++) {
            // do things to your newly added nodes here
            var $node = $(mutation.addedNodes[i]).find('button.player-button--theatre');
            if ($node.length) {
                $node.trigger('click');
                observer.disconnect();
                return true;
            }
        }
    });
});

function startObserver() {
    observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: false,
        characterData: false
    });
}

startObserver();

window.onpopstate = function (event) {
    startObserver();
};

Switch to Array.some instead of Array.forEach


import Ember from 'ember';

export default Ember.Component.extend({
  classNameBindings: [':as-calendar-header'],
  tagName: 'header',

  isInCurrentWeek: Ember.computed.oneWay('model.isInCurrentWeek'),
  model: null,
  title: '',

  actions: {
    navigateWeek: function(index) {
      this.get('model').navigateWeek(index);

      if (this.attrs['onNavigateWeek']) {
        this.attrs['onNavigateWeek'](index);
      }
    },

    goToCurrentWeek: function() {
      this.get('model').goToCurrentWeek();
    }
  }
});

import Ember from 'ember';

export default Ember.Component.extend({
  classNameBindings: [':as-calendar-header'],
  tagName: 'header',

  isInCurrentWeek: Ember.computed.oneWay('model.isInCurrentWeek'),
  model: null,
  title: '',

  actions: {
    navigateWeek: function(index) {
      this.get('model').navigateWeek(index);

      if (this.attrs['onNavigateWeek']) {
        this.attrs['onNavigateWeek'](index);
      }
    },

    goToCurrentWeek: function() {
      this.get('model').goToCurrentWeek();

      if (this.attrs['onNavigateWeek']) {
        this.attrs['onNavigateWeek'](0);
      }
    }
  }
});

Make 'This week' button trigger onNavigateWeek with index 0


'use strict';

angular.module('Teem')
  .factory('NewForm', [
  '$location', '$window',
  function($location, $window) {
    var scope,
        objectName,
        scopeFn = {
          isNew () {
            return $location.search().form === 'new';
          },
          cancelNew () {
            scope[objectName].delete();

            $window.history.back();
          },
          confirmNew () {
            $location.search('form', undefined);
          }
        };

    function initialize(s, o) {
      scope = s;
      objectName = o;

      Object.assign(scope, scopeFn);
    }

    return {
      initialize
    };
  }]);

'use strict';

angular.module('Teem')
  .factory('NewForm', [
  '$location', '$window',
  function($location, $window) {
    var scope,
        objectName,
        scopeFn = {
          isNew () {
            return $location.search().form === 'new';
          },
          cancelNew () {
            scope[objectName].delete();

            $location.search('form', undefined);

            $window.history.back();
          },
          confirmNew () {
            $location.search('form', undefined);
          }
        };

    function initialize(s, o) {
      scope = s;
      objectName = o;

      Object.assign(scope, scopeFn);
    }

    return {
      initialize
    };
  }]);

Remove search from location on cancel


import Reflux from 'reflux'
import api from 'data/api'

const DatapointActions = Reflux.createActions({
  'fetchDatapoints': { children: ['completed', 'failed'], asyncResult: true },
  'clearDatapoints': 'clearDatapoints'
})

// API CALLS
// ---------------------------------------------------------------------------
DatapointActions.fetchDatapoints.listen(params => {
  const query = _prepDatapointsQuery(params)
  DatapointActions.fetchDatapoints.promise(api.datapoints(query))
})

// ACTION HELPERS
// ---------------------------------------------------------------------------
const _prepDatapointsQuery = (params) => {
  let query = {
    indicator__in: params.indicator_ids,
    campaign_start: params.start_date,
    campaign_end: params.end_date,
    chart_type: params.type,
    chart_uuid: params.uuid
  }

  if (params.type === 'ChoroplethMap' || params.type === 'MapChart' || params.type === 'BubbleMap') {
    query['parent_location_id__in'] = params.location_ids
  } else {
    query['location_id__in'] = params.location_ids
  }

  if (params.indicator_filter) {
    query['filter_indicator'] = params.indicator_filter.type
    query['filter_value'] = params.indicator_filter.value
  }

  return query
}

export default DatapointActions

import Reflux from 'reflux'
import api from 'data/api'

const DatapointActions = Reflux.createActions({
  'fetchDatapoints': { children: ['completed', 'failed'], asyncResult: true },
  'clearDatapoints': 'clearDatapoints'
})

// API CALLS
// ---------------------------------------------------------------------------
DatapointActions.fetchDatapoints.listen(params => {
  const query = _prepDatapointsQuery(params)
  DatapointActions.fetchDatapoints.promise(api.datapoints(query))
})

// ACTION HELPERS
// ---------------------------------------------------------------------------
const _prepDatapointsQuery = (params) => {
  let query = {
    indicator__in: params.indicator_ids,
    campaign_start: params.start_date,
    campaign_end: params.end_date,
    chart_type: params.type,
    chart_uuid: params.uuid
  }

  const type = params.type
  const needsChildrenLocations = type === 'ChoroplethMap' || type === 'MapChart' || type === 'BubbleMap' || type === 'TableChart'

  if (needsChildrenLocations) {
    query['parent_location_id__in'] = params.location_ids
  } else {
    query['location_id__in'] = params.location_ids
  }

  if (params.indicator_filter) {
    query['filter_indicator'] = params.indicator_filter.type
    query['filter_value'] = params.indicator_filter.value
  }

  return query
}

export default DatapointActions

Add parent_location_id to TableChart datapoints


/**
 * @fileoverview Run the bootstrap service
 */

var port = 3020,
    system = require('system'),
    page = require('webpage').create(),
    server = require('./server').create(port),
    util = require('./util'),
    module = system.args[1],
    config = system.args[2];

if (!module) {
    console.error('missing module');
    phantom.exit(1);
}

if (!config) {
    console.error('missing config');
    phantom.exit(1);
}

config = decodeURIComponent(config);
var url = 'http://localhost:' + port + '/' + module + '.html?config=' + config;
page.open(url, function(status) {

    if (status !== 'success') {
        console.error('Page could not be opened');
        phantom.exit(1);
    }

    // TODO(rrp): Generalize this bit
    // Wait for fyre-comment-stream el? (need to ensure 100% loaded somehow)
    util.waitFor(function() {
        return page.evaluate(function() {
            return document.getElementsByClassName('fyre-comment-stream').length > 0;
        });
    }, function() {
        var html = page.evaluate(function() {
            return document.getElementById('bs').innerHTML;
        });
        console.log(html);
        phantom.exit();
    });
});

/**
 * @fileoverview Run the bootstrap service
 */

var port = 3020,
    system = require('system'),
    page = require('webpage').create(),
    server = require('./server').create(port),
    util = require('./util'),
    module = system.args[1],
    config = system.args[2];

if (!module) {
    console.error('missing module');
    phantom.exit(1);
}

if (!config) {
    console.error('missing config');
    phantom.exit(1);
}

config = decodeURIComponent(config);
var url = 'http://localhost:' + port + '/' + module + '.html?config=' + config;
console.log('<!-- html generated by Livefyre -->');
page.open(url, function(status) {
    if (status !== 'success') {
        console.error('Page could not be opened');
        phantom.exit(1);
    }

    // TODO(rrp): Generalize this bit
    // Wait for fyre-comment-stream el? (need to ensure 100% loaded somehow)
    util.waitFor(function() {
        return page.evaluate(function() {
            return document.getElementsByClassName('fyre-comment-stream').length > 0;
        });
    }, function() {
        var html = page.evaluate(function() {
            return document.getElementById('bs').innerHTML;
        });
        console.log(html);
        phantom.exit();
    });
});

Add html generated by lf comment in bs documents


// Default values for form fields.
export const ACTIVITY_TITLE_PLACEHOLDER = 'What will you be doing?';
export const ACTIVITY_DESCRIPTION_PLACEHOLDER = 'Add some details!';

// Default and placeholder values for form fields.
export const ACTIVITY_TITLE_PLACEHOLDER = 'What will you be doing?';
export const ACTIVITY_DESCRIPTION_PLACEHOLDER = 'Add some details!';

export const TRIPS_TITLE_DEFAULT = 'Untitled Trip';
export const TRIPS_DESTINATION_DEFAULT = 'No Destination';
export const TRIPS_TITLE_PLACEHOLDER = 'Title your trip!';
export const TRIPS_DESCRIPTION_PLACEHOLDER = 'Add some details!';
export const TRIPS_DESTINATION_PLACEHOLDER = 'Where will you be going?';
export const TRIPS_COLLAB_EMAIL_PLACEHOLDER = 'person@email.xyz';

Add default and placeholder value for save trip modal.


angular.module('codebrag.auth')

    .factory('authService', function($http, httpRequestsBuffer, $q, $rootScope, events) {

        var authService = {

            loggedInUser: undefined,

            login: function(user) {
                var loginRequest = $http.post('rest/users', user, {bypassQueue: true});
                return loginRequest.then(function(response) {
                    authService.loggedInUser = response.data;
                    httpRequestsBuffer.retryAllRequest();
                });
            },

            logout: function() {
                var logoutRequest = $http.get('rest/users/logout');
                return logoutRequest.then(function() {
                    authService.loggedInUser = undefined;
                })
            },

            isAuthenticated: function() {
                return !angular.isUndefined(authService.loggedInUser);
            },

            isNotAuthenticated: function() {
                return !authService.isAuthenticated();
            },

            requestCurrentUser: function() {
                if (authService.isAuthenticated()) {
                    return $q.when(authService.loggedInUser);
                }
                var promise = $http.get('rest/users');
                return promise.then(function(response) {
                    authService.loggedInUser = response.data;
                    $rootScope.$broadcast(events.loggedIn);
                    return $q.when(authService.loggedInUser);
                });
            }

        };

        return authService;

    });

angular.module('codebrag.auth')

    .factory('authService', function($http, httpRequestsBuffer, $q, $rootScope, events) {

        var authService = {

            loggedInUser: undefined,

            login: function(user) {
                var loginRequest = $http.post('rest/users', user, {bypassQueue: true});
                return loginRequest.then(function(response) {
                    authService.loggedInUser = response.data;
                    $rootScope.$broadcast(events.loggedIn);
                    httpRequestsBuffer.retryAllRequest();
                });
            },

            logout: function() {
                var logoutRequest = $http.get('rest/users/logout');
                return logoutRequest.then(function() {
                    authService.loggedInUser = undefined;
                })
            },

            isAuthenticated: function() {
                return !angular.isUndefined(authService.loggedInUser);
            },

            isNotAuthenticated: function() {
                return !authService.isAuthenticated();
            },

            requestCurrentUser: function() {
                if (authService.isAuthenticated()) {
                    return $q.when(authService.loggedInUser);
                }
                var promise = $http.get('rest/users');
                return promise.then(function(response) {
                    authService.loggedInUser = response.data;
                    $rootScope.$broadcast(events.loggedIn);
                    return $q.when(authService.loggedInUser);
                });
            }

        };

        return authService;

    });

Add broadcasting of login event for non-github login


/*
 * CSS Modal Plugin for HTML5 Video (play/pause)
 * Author: Anselm Hannemann
 * Date: 2014-02-04
 */

(function (global) {

	'use strict';

	var CSSModal = global.CSSModal;

	// If CSS Modal is still undefined, throw an error
	if (!CSSModal) {
		throw new Error('Error: CSSModal is not loaded.');
	}

	var videos;

	// Enables Auto-Play when calling modal
	CSSModal.on('cssmodal:show', document, function (event) {
		// Fetch all video elements in active modal
		videos = CSSModal.activeElement.querySelectorAll('video');

		if (videos.length > 0) {
			// Play first video in modal
			videos[0].play();
		}
	});

	// If modal is closed, pause all videos
	CSSModal.on('cssmodal:hide', document, function (event) {
		var i = 0;

		if (videos.length > 0) {
			// Pause all videos in active modal
			for (; i < videos.length; i++) {
				videos[i].pause();
			}
		}
	});

}(window));

/*
 * CSS Modal Plugin for HTML5 Video (play/pause)
 * Author: Anselm Hannemann
 * Date: 2014-02-04
 */

(function (global) {

	'use strict';

	var CSSModal = global.CSSModal;
	var videos;

	// If CSS Modal is still undefined, throw an error
	if (!CSSModal) {
		throw new Error('Error: CSSModal is not loaded.');
	}

	// Enables Auto-Play when calling modal
	CSSModal.on('cssmodal:show', document, function () {

		// Fetch all video elements in active modal
		videos = CSSModal.activeElement.querySelectorAll('video');

		// Play first video in modal
		if (videos.length > 0) {
			videos[0].play();
		}
	});

	// If modal is closed, pause all videos
	CSSModal.on('cssmodal:hide', document, function () {
		var i = 0;

		// Pause all videos in active modal
		if (videos.length > 0) {
			for (; i < videos.length; i++) {
				videos[i].pause();
			}
		}
	});

}(window));

Fix HTML5 Video plugin JSHint errors


module.exports = {
  normalizeEntityName: function() {},

  afterInstall: function() {
    return this.addBowerPackageToProject('fullcalendar', '^2.7.3').then(function () {
      return this.addBowerPackageToProject('fullcalendar-scheduler', '^1.3.2');
    });
  }
};

module.exports = {
  normalizeEntityName: function() {},

  afterInstall: function() {
    return this.addBowerPackageToProject('fullcalendar', '^2.7.3').then(() => {
      return this.addBowerPackageToProject('fullcalendar-scheduler', '^1.3.2');
    });
  }
};

Fix second regression in blueprint.


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

/**
 * The Search Results component
 *
 * @disable-docs
 */
const SearchResults = ( page ) => {

	return (

{ page.heading }

 results for [query]

						<form className="search__searchbox" role="search" autoComplete="off" action="/search" method="get">
							<input type="search" className="au-text-input" name="text-input" id="text-input" placeholder="Digital Guides"/>
							<input type="submit" className="au-btn au-btn--light icon icon--search" value="Search" />
						</form>

	);
}

SearchResults.propTypes = {
	/**
	 * _body: (partials)(4)
	 */
	_body: PropTypes.node.isRequired,
};

SearchResults.defaultProps = {};

export default SearchResults;

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

/**
 * The Search Results component
 *
 * @disable-docs
 */
const SearchResults = ( page ) => {

	return (

{ page.heading }

 results for [query]

						<form className="search__searchbox" role="search" autoComplete="off" action="/search" method="get">
							<input type="search" className="au-text-input" name="q" id="text-input" placeholder="Digital Guides"/>
							<input type="submit" className="au-btn au-btn--light icon icon--search" value="Search" />
						</form>

	);
}

SearchResults.propTypes = {
	/**
	 * _body: (partials)(4)
	 */
	_body: PropTypes.node.isRequired,
};

SearchResults.defaultProps = {};

export default SearchResults;

Use name =q (fix the onpage search)


!function(exports) {
  'use strict';

  // Gets textures from URLs.
  // Keeps LRU cache so that textures are rebound as infrequently as possible.
  // How to implement LRU cache:
  // * Check if raster texture maps to id in texture slot
  // * If yes, awesome
  // * If no, rebind to least most recently use texture
  // * Implement lru texture as a linked list duh
  // * Slots in tex array point to { id, iterator } tuples
  function TextureMap() {
  }

  TextureMap.prototype.fromUrl = function() {};

  function normalizeUrl(url) {
  }

  exports.TextureMap = TextureMap;

}(demo);

!function(exports) {
  'use strict';

  // Gets textures from URLs.
  // Keeps LRU cache so that textures are rebound as infrequently as possible.
  // How to implement LRU cache:
  // * Check if raster texture maps to id in texture slot
  // * If yes, awesome
  // * If no, rebind to least most recently use texture
  // * Implement lru texture as a linked list duh
  // * Slots in tex array point to { id, iterator } tuples
  //
  // Note: use a scoring algorithm, NOT strict LRU. Every time something is
  // used, it gets its score bumped. The list is the top 32 scoring textures: to
  // get into the list, you need to beat the score of the lowest one. Add some
  // sort of decay to the algorithm so that previously-hot but now cold textures
  // get ejected relatively quickly.
  function TextureMap() {
  }

  TextureMap.prototype.fromUrl = function() {};

  function normalizeUrl(url) {
  }

  exports.TextureMap = TextureMap;

}(demo);

Add note about scoring algorithms for tex cache


'use strict';

var path = process.cwd();
var Graphriend = require(path + '/app/controllers/Graphriend.server.js');
var sess;

module.exports = function (app) {

	function isLoggedIn (req, res, next) {
		sess = req.session;
		if (sess.user) {
			return next();
		} else {
			res.redirect('/');
		}
	}

	var graPhriend = new Graphriend();

	var user = {
		isLogged: false,
		name: 'Jinme',
		username: 'mirabalj'
	}

	app.route('/')
		.get(function (req, res) {
			res.render('main', { user: user, page: 'index' });
		});

	app.post('/api/signup', graPhriend.signUp);
	app.post('/api/login', graPhriend.logIn);

/* Example Authenticated verify
	app.route('/profile')
		.get(isLoggedIn, function (req, res) {
			res.render('main', { user: sess.user, page: 'profile' });
		});
*/

/* Example REST api
	app.route('/friends')
		.get(isLoggedIn, graPhriend.getFriend)
		.post(isLoggedIn, graPhriend.addFriend)
		.delete(isLoggedIn, graPhriend.delFriend);
*/

};

'use strict';

var path = process.cwd();
var Graphriend = require(path + '/app/controllers/Graphriend.server.js');
var sess;

module.exports = function (app) {

	function isLoggedIn (req, res, next) {
		sess = req.session;
		if (sess.user || req.url === '/') {
			return next();
		} else {
			res.redirect('/');
		}
	}

	var graPhriend = new Graphriend();

	var user = {
		isLogged: false,
		name: 'Jinme',
		username: 'mirabalj'
	}

	app.route('/')
		.get(isLoggedIn, function (req, res) {
			res.render('main', { user: sess.user, page: 'index' });
		});

	app.post('/api/signup', graPhriend.signUp);
	app.post('/api/login', graPhriend.logIn);

/* Example Authenticated verify
	app.route('/profile')
		.get(isLoggedIn, function (req, res) {
			res.render('main', { user: sess.user, page: 'profile' });
		});
*/

/* Example REST api
	app.route('/friends')
		.get(isLoggedIn, graPhriend.getFriend)
		.post(isLoggedIn, graPhriend.addFriend)
		.delete(isLoggedIn, graPhriend.delFriend);
*/

};

Change main route to get session user


import Ember from 'ember';
import { inject as service } from '@ember/service';
import config from '../config/environment';

export default Ember.Route.extend({
  queryParams: {
    rd: {
      refreshModel: true
    }
  },
  routerService: service('-routing'),
  model: function(params) {
    // console.log("In login route");
    var http = location.protocol;
    var slashes = http.concat("//");
    var ishttp = (location.port === '') || (location.port === 80) || (location.port === 443);
    var host = slashes.concat(window.location.hostname) + (ishttp? "": ':'+location.port);
    var pathSuffix = decodeURIComponent(params.rd) || "";
    var redirectUrl = host;
    // Append return route if one exists, ignore login route
    if (pathSuffix && pathSuffix.indexOf('/login') === -1) {
      redirectUrl += pathSuffix
    }
    // Append to query string if one exists, otherwise add one
    if (redirectUrl.indexOf("?") !== -1) {
      redirectUrl += "&token={girderToken}"
    } else {
      redirectUrl += "?token={girderToken}"
    }
    let url = config.apiUrl + '/oauth/provider?redirect=' + encodeURIComponent(redirectUrl);

    return Ember.$.getJSON(url);
  }
});

import Ember from 'ember';
import { inject as service } from '@ember/service';
import config from '../config/environment';

export default Ember.Route.extend({
  queryParams: {
    rd: {
      refreshModel: true
    }
  },
  routerService: service('-routing'),
  model: function(params) {
    // console.log("In login route");
    var http = location.protocol;
    var slashes = http.concat("//");
    var ishttp = (location.port === '') || (location.port === 80) || (location.port === 443);
    var host = slashes.concat(window.location.hostname) + (ishttp? "": ':'+location.port);
    var pathSuffix = decodeURIComponent(params.rd || "");
    var redirectUrl = host;
    // Append return route if one exists, ignore login route
    if (pathSuffix && pathSuffix.indexOf('/login') === -1) {
      redirectUrl += pathSuffix
    }
    // Append to query string if one exists, otherwise add one
    if (redirectUrl.indexOf("?") !== -1) {
      redirectUrl += "&token={girderToken}"
    } else {
      redirectUrl += "?token={girderToken}"
    }
    let url = config.apiUrl + '/oauth/provider?redirect=' + encodeURIComponent(redirectUrl);

    return Ember.$.getJSON(url);
  }
});

Handle undefined/null rd - encodeURIComponent apparently returns a string in such cases -_-*


angular.module('materialscommons').component('mcExperimentTaskDetails', {
    templateUrl: 'app/project/experiments/experiment/components/tasks/mc-experiment-task-details.html',
    controller: MCExperimentTaskDetailsComponentController,
    bindings: {
        task: '='
    }
});

/*@ngInject*/
function MCExperimentTaskDetailsComponentController($scope, editorOpts, currentTask, templates,
                                                    template, experimentsService, $stateParams, toast) {
    let ctrl = this;
    ctrl.currentTask = currentTask.get();
    var t = templates.getTemplate('As Received');
    template.set(t);

    $scope.editorOptions = editorOpts({height: 25, width: 20});

    ctrl.selectedTemplate = (templateId, processId) => {
        console.log('selectedTemplate', templateId, processId);
    };

    ctrl.updateTaskNote = () => {
        console.log('updateTaskNote');
        if (ctrl.task.note === null) {
            ctrl.task.note = "";
        }

        experimentsService.updateTask($stateParams.project_id, $stateParams.experiment_id, ctrl.task.id,
            {note: ctrl.task.note})
            .then(
                () => null,
                () => toast.error('Unable to update task note.')
            );
    };
}

angular.module('materialscommons').component('mcExperimentTaskDetails', {
    templateUrl: 'app/project/experiments/experiment/components/tasks/mc-experiment-task-details.html',
    controller: MCExperimentTaskDetailsComponentController,
    bindings: {
        task: '='
    }
});

/*@ngInject*/
function MCExperimentTaskDetailsComponentController($scope, editorOpts, currentTask, templates,
                                                    template, experimentsService, $stateParams, toast) {
    let ctrl = this;
    ctrl.currentTask = currentTask.get();
    var t = templates.getTemplate('As Received');
    template.set(t);

    $scope.editorOptions = editorOpts({height: 25, width: 20});

    ctrl.selectedTemplate = (templateId, processId) => {
        console.log('selectedTemplate', templateId, processId);
    };

    ctrl.updateTaskNote = () => {
        if (ctrl.task.note === null) {
            return;
        }

        experimentsService.updateTask($stateParams.project_id, $stateParams.experiment_id, ctrl.task.id,
            {note: ctrl.task.note})
            .then(
                () => null,
                () => toast.error('Unable to update task note.')
            );
    };
}

Return if note is null.


WebApp.connectHandlers.use("/package", function(request, response) {
  var url = `https://atmospherejs.com/a/packages/findByNames\
?names=${request.url.split('/')[1]}`;
  var opts = {headers: {'Accept': 'application/json'}};
  HTTP.get(url, opts, function(err, res) {
    var name = '', version, pubDate, starCount, installYear;
    var pl = res.data[0];

    if (res.data.length !== 0) {
      name = pl.name;
      version = pl.latestVersion.version;
      pubDate = moment(pl.latestVersion.published.$date).format('MMM Do YYYY');
      starCount = pl.starCount || 0;
      installYear = pl['installs-per-year'] || 0;
    }

    SSR.compileTemplate('icon', Assets.getText('icon.svg'));
    var width = 225 + name.length * 6.305555555555555;
    var icon = SSR.render('icon', {w: width, totalW: width+2, n: name,
      v: version, p: pubDate, s: starCount, i: installYear});

    response.writeHead(200, {"Content-Type": "image/svg+xml"});
    response.end(icon);
  });
});

WebApp.connectHandlers.use("/package", function(request, response) {
  var url = `https://atmospherejs.com/a/packages/findByNames\
?names=${request.url.split('/')[1]}`;
  var opts = {headers: {'Accept': 'application/json'}};
  HTTP.get(url, opts, function(err, res) {
    var name = '', pl = res.data[0], version, pubDate, starCount, installYear;

    if (res.data.length !== 0) {
      name = pl.name;
      version = pl.latestVersion.version;
      pubDate = moment(pl.latestVersion.published.$date).format('MMM Do YYYY');
      starCount = pl.starCount || 0;
      installYear = pl['installs-per-year'] || 0;
    }

    SSR.compileTemplate('icon', Assets.getText('icon.svg'));
    var width = 225 + name.length * 6.305555555555555;
    var icon = SSR.render('icon', {w: width, totalW: width+2, n: name,
      v: version, p: pubDate, s: starCount, i: installYear});

    response.writeHead(200, {"Content-Type": "image/svg+xml"});
    response.end(icon);
  });
});

Use inline variable declartion to save LOC


var path = require('path');
var webpackSettings = require('../../webpack-helper');

module.exports = webpackSettings({
  entry: './js/app',
  output: {
    filename: './js/app.min.js',
    path: path.resolve('./js')
  },
  resolve: {
    alias: {
      // Tungsten.js doesn't need jQuery, but backbone needs a subset of jQuery APIs.  Backbone.native
      // implements tha minimum subset of required functionality
      'jquery': 'backbone.native',
      //  Aliases for the current version of tungstenjs above the ./examples directory.  If
      //  examples dir is run outside of main tungstenjs repo, remove these aliases
      //  and use via normal modules directories (e.g., via NPM)
      'tungstenjs/adaptors/backbone': path.join(__dirname, '../../adaptors/backbone'),
      'tungstenjs/src/template/template': path.join(__dirname, '../../src/template/template'),
      'tungstenjs': '../../src'
    }
  },
  resolveLoader: {
    root: path.join(__dirname, 'node_modules'),
    modulesDirectories: ['node_modules', path.join(__dirname, '../../node_modules/')]
  },
  devtool: '#source-map',
  loaders: [{test: /\.js$/, loader: 'babel?stage=0', exclude: /node_modules/}]
});

var path = require('path');
var webpackSettings = require('../../webpack-helper');

module.exports = webpackSettings({
  entry: './js/app',
  output: {
    filename: './js/app.min.js',
    path: path.resolve('./js')
  },
  resolve: {
    alias: {
      // Tungsten.js doesn't need jQuery, but backbone needs a subset of jQuery APIs.  Backbone.native
      // implements tha minimum subset of required functionality
      'jquery': 'backbone.native',
      //  Aliases for the current version of tungstenjs above the ./examples directory.  If
      //  examples dir is run outside of main tungstenjs repo, remove these aliases
      //  and use via normal modules directories (e.g., via NPM)
      'tungstenjs/adaptors/backbone': path.join(__dirname, '../../adaptors/backbone'),
      'tungstenjs/src/template/template': path.join(__dirname, '../../src/template/template'),
      'tungstenjs': '../../src'
    }
  },
  resolveLoader: {
    root: path.join(__dirname, 'node_modules'),
    modulesDirectories: ['node_modules', path.join(__dirname, '../../node_modules/')]
  },
  devtool: '#source-map',
  module: {
    loaders: [{test: /\.js$/, loader: 'babel?stage=0', exclude: /node_modules/}]
  }
});

Fix for webpack es6 example loader