// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
'use strict';

module.exports = function createDebugClearHandler(ringpop) {
    return function handleDebugClear(arg1, arg2, hostInfo, callback) {
        ringpop.config.set('gossipLogLevel', 'debug');
        callback(null, null, 'ok');
    };
};

// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
'use strict';

module.exports = function createDebugClearHandler(ringpop) {
    return function handleDebugClear(arg1, arg2, hostInfo, callback) {
        ringpop.config.set('gossipLogLevel', 'off');
        callback(null, null, 'ok');
    };
};

Update /admin/debug/clear with new logging semantics


define([
    'underscore',
    'js-whatever/js/location'
], function (_, location) {
    "use strict";

    function supported (configuration, attributes) {
        return configuration.mmapBaseUrl
            && attributes.mmapUrl
            && attributes.mmapEventSourceType
            && attributes.mmapEventSourceName
            && attributes.mmapEventTime;
    }

    const baseUrlRegex = /(?:\w+:\/\/)?([^:/]+(?::\d+)?)(?:\/[^/]+)*/;

    function canBeReused (configuration) {
        return baseUrlRegex.exec(configuration.mmapBaseUrl)[1] === baseUrlRegex.exec(location.host())[1];
    }

    return function (configuration) {
        let childWindow;

        return {
            supported: _.partial(supported, configuration),
            canBeReused: _.partial(canBeReused, configuration),
            open: function (attributes) {
                if (supported(configuration, attributes)) {
                    if (canBeReused(configuration) && childWindow && !childWindow.closed) {
                        const sourceType = attributes.mmapEventSourceType;
                        const sourceName = attributes.mmapEventSourceName;
                        const startTime = attributes.mmapEventTime;
                        if (sourceType === 'Camera') {
                            //noinspection JSUnresolvedFunction
                            childWindow.loadCamera(sourceName, startTime);
                        } else {
                            //noinspection JSUnresolvedFunction
                            childWindow.loadChannel(sourceName, startTime);
                        }
                        childWindow.focus();
                    } else {
                        childWindow = window.open(configuration.mmapBaseUrl + attributes.mmapUrl);
                    }
                }
            }
        }
    }
});

define([
    'underscore',
    'js-whatever/js/location'
], function (_, location) {
    "use strict";

    function supported (configuration, attributes) {
        return configuration.mmapBaseUrl
            && attributes.mmapUrl
            && attributes.mmapEventSourceType
            && attributes.mmapEventSourceName
            && attributes.mmapEventTime;
    }

    const baseUrlRegex = /(?:\w+:\/\/)?([^:/]+(?::\d+)?)(?:\/[^/]+)*/;

    function canBeReused (configuration) {
        return configuration.mmapBaseUrl
            && location.host()
            && baseUrlRegex.exec(configuration.mmapBaseUrl)[1] === baseUrlRegex.exec(location.host())[1];
    }

    return function (configuration) {
        let childWindow;

        return {
            supported: _.partial(supported, configuration),
            canBeReused: _.partial(canBeReused, configuration),
            open: function (attributes) {
                if (supported(configuration, attributes)) {
                    if (canBeReused(configuration) && childWindow && !childWindow.closed) {
                        const sourceType = attributes.mmapEventSourceType;
                        const sourceName = attributes.mmapEventSourceName;
                        const startTime = attributes.mmapEventTime;
                        if (sourceType === 'Camera') {
                            //noinspection JSUnresolvedFunction
                            childWindow.loadCamera(sourceName, startTime);
                        } else {
                            //noinspection JSUnresolvedFunction
                            childWindow.loadChannel(sourceName, startTime);
                        }
                        childWindow.focus();
                    } else {
                        childWindow = window.open(configuration.mmapBaseUrl + attributes.mmapUrl);
                    }
                }
            }
        }
    }
});

Handle location.host being null (FIND-733)

[rev. matthew.gordon]


const minimist = require('minimist');
const options = minimist(process.argv.slice(2));
const isProduction = options.env === 'production';

let config = {
  console_options: options,
  isProduction: isProduction,

  src: {
    js: './src/js/**/*.js',
    vue: {
      // src : dist
      './src/js/app.js': 'app.js',
      './src/js/train-number-calc.js': 'train-number-calc.js',
    },
    vue_watch: './src/js/**/*.{js,vue}',
    eslint: './src/js/**/*.{js,vue}',
    scss: './src/scss/**/*.scss',
    lib: {
      js: [
        './node_modules/jquery/dist/jquery.min.js',
        './node_modules/bootstrap/dist/js/bootstrap.min.js',
      ],
    },
  },

  dist: {
    js: './assets/js',
    css: './assets/css',
  },

  map: './.map',

  lib: {
    js: 'lib.js',
  },

  options: {
    eslint: {
      configFile: '.eslintrc.js',
    },
  },

  plugins: require('gulp-load-plugins')(),
};

module.exports = config;

const minimist = require('minimist');
const options = minimist(process.argv.slice(2));
const isProduction = options.env === 'production';

let config = {
  console_options: options,
  isProduction: isProduction,

  src: {
    js: './src/js/**/*.js',
    vue: {
      // src : dist
      './src/js/app.js': 'app.js',
      './src/js/train-number-calc.js': 'train-number-calc.js',
    },
    vue_watch: './src/js/**/*.{js,vue}',
    eslint: './src/js/**/*.{js,vue}',
    scss: './src/scss/**/*.scss',
    lib: {
      js: [
        './node_modules/jquery/dist/jquery.slim.min.js',
        './node_modules/bootstrap/dist/js/bootstrap.min.js',
      ],
    },
  },

  dist: {
    js: './assets/js',
    css: './assets/css',
  },

  map: './.map',

  lib: {
    js: 'lib.js',
  },

  options: {
    eslint: {
      configFile: '.eslintrc.js',
    },
  },

  plugins: require('gulp-load-plugins')(),
};

module.exports = config;

Use the slim jquery file

Use the slim jquery file


export const reduceGraphComplexity = (cy) => {
  const compartmentChildren = cy.nodes('[class="compartment"]').children();
  compartmentChildren.filterFn((ele) => ele.neighborhood().length === 0).remove();

  const danglingNodes = cy.nodes('[class != "compartment"], [class != "complex"], [class != "complex multimer"]');
  danglingNodes.filterFn((ele) => !ele.isChild() && ele.neighborhood.length === 0).remove();

  const api = cy.expandCollapse('get');
  const complexes = cy.nodes('[class="complex"], [class="complex multimer"]');
  api.collapseRecursively(complexes);

};

export const reduceGraphComplexity = (cy) => {
  const api = cy.expandCollapse('get');
  const complexes = cy.nodes('[class="complex"], [class="complex multimer"]');
  api.collapseRecursively(complexes);

};

Remove unnecessary code; Server handles this filtering case


const minimist = require('minimist');
const options = minimist(process.argv.slice(2));
const isProduction = (() => {
  const env = options.env;

  return env === undefined ? false : env.startsWith('prod');
})();

if (isProduction) {
  console.log('Enable production mode.');
}

let config = {
  console_options: options,
  isProduction: isProduction,

  src: {
    js: './src/js/**/*.js',
    vue: {
      // src : dist
      './src/js/app.js': 'app.js',
      './src/js/train-number-calc.js': 'train-number-calc.js',
    },
    vue_watch: './src/js/**/*.{js,vue}',
    eslint: './src/js/**/*.{js,vue}',
    scss: './src/scss/**/*.scss',
    lib: {
      js: [
        './node_modules/jquery/dist/jquery.slim.min.js',
        './node_modules/popper.js/dist/popper.min.js',
        './node_modules/bootstrap/dist/js/bootstrap.min.js',
      ],
    },
  },

  dist: {
    js: './assets/js',
    css: './assets/css',
  },

  map: './.map',

  lib: {
    js: 'lib.js',
  },

  options: {
    eslint: {
      configFile: '.eslintrc.js',
    },
  },

  plugins: require('gulp-load-plugins')(),
};

module.exports = config;

const minimist = require('minimist');
const options = minimist(process.argv.slice(2));
const isProduction = (() => {
  const env = options.env;

  return env === undefined ? false : env.startsWith('prod');
})();

if (isProduction) {
  console.log('Enable production mode.');
}

let config = {
  console_options: options,
  isProduction: isProduction,

  src: {
    js: './src/js/**/*.js',
    vue: {
      // src : dist
      './src/js/app.js': 'app.js',
      './src/js/train-number-calc.js': 'train-number-calc.js',
    },
    vue_watch: './src/js/**/*.{js,vue}',
    eslint: './src/js/**/*.{js,vue}',
    scss: './src/scss/**/*.scss',
    lib: {
      js: [
        './node_modules/jquery/dist/jquery.slim.min.js',
        './node_modules/bootstrap/dist/js/bootstrap.bundle.min.js',
      ],
    },
  },

  dist: {
    js: './assets/js',
    css: './assets/css',
  },

  map: './.map',

  lib: {
    js: 'lib.js',
  },

  options: {
    eslint: {
      configFile: '.eslintrc.js',
    },
  },

  plugins: require('gulp-load-plugins')(),
};

module.exports = config;

Revert "Fix lib js files"

Revert "Fix lib js files"

This reverts commit 059ea63


const Amqp = require('amqplib/callback_api');

module.exports = function Channel(url, opts, done) {
  Amqp.connect(url, opts, (err, conn) => {
    if (err) return done(err);

    conn.createChannel((err, ch) => {
      if (err) return done(err);

      done(null, ch, conn);
    });
  });
};

const Amqp = require('amqplib/callback_api');

module.exports = function Channel(url, opts, done) {
  Amqp.connect(url, opts, function (err, conn) {
    if (err) return done(err);

    conn.createChannel(function (err, ch) {
      if (err) return done(err);

      done(null, ch, conn);
    });
  });
};

Remove fat arrow function expressions

Remove fat arrow function expressions


/**
 * Higher order function to make another function only be invoked when user is deemed idle.
 * Wraps around the web extension browser.idle API.
 *
 * @param {function} task Async or sync function to run after idle.
 * @param {number} [idleTimeout=15] Number of seconds to consider user idle (min is 15)
 */
export const makeDelayedTask = (task, idleTimeout = 15) => () => {
    browser.idle.setDetectionInterval(idleTimeout)

    async function runWhenIdle(idleState) {
        if (idleState === 'idle') {
            await task()
            // Make sure to remove listner (itself) after runnings once
            browser.idle.onStateChanged.removeListener(runWhenIdle)
        }
    }

    browser.idle.onStateChanged.addListener(runWhenIdle)
}

/**
 * Higher order function to make another function only be invoked when user is deemed idle.
 * Wraps around the web extension browser.idle API.
 *
 * @param {(any) => Promise<any>} task Async or sync function to run after idle.
 * @param {number} [idleTimeout=15] Number of seconds to consider user idle (min is 15)
 * @return {(any) => Promise<any>} Augmented version of `task` that, when invoked, will only run when user idle.
 *  A Promise will be returned which the invoker can use to wait for eventual output.
 */
export const makeDelayedTask = (task, idleTimeout = 15) => (...args) => new Promise((resolve, reject) => {
    browser.idle.setDetectionInterval(idleTimeout)

    async function runWhenIdle(idleState) {
        if (idleState === 'idle') {
            try {
                const output = await task(...args)
                resolve(output)
            } catch (error) {
                reject(error)
            } finally { // Make sure to remove listner (itself) after running once
                browser.idle.onStateChanged.removeListener(runWhenIdle)
            }
        }
    }

    browser.idle.onStateChanged.addListener(runWhenIdle)
})

Make makeDelayedTask return fn with same signature

- now returns a Promise returning fn that resolves to whatever the original function does
- allow any args to be passed to the delayed function


import * as Backbone from 'backbone';
import SearchBoxView from '../views/searchBox-view.js';
import SearchResultsView from '../views/searchResults-view.js';
import dispatcher from '../helpers/dispatcher.js';

class AppRouter extends Backbone.Router {

  get routes() {
    return {
      '': 'loadDefault',
      'search/results': 'showSearchResults'
    };
  }

  initialize() {
    window.console.log('Router initialized');
    this.listenTo(dispatcher, 'router:go', this.go);
  }

  loadDefault() {
    new SearchBoxView();
  }

  showSearchResults() {
    new SearchResultsView();
  }

}

export default AppRouter;

import * as Backbone from 'backbone';
import SearchBoxView from '../views/searchBox-view.js';
import SearchResultsView from '../views/searchResults-view.js';
import dispatcher from '../helpers/dispatcher.js';

class AppRouter extends Backbone.Router {

  get routes() {
    return {
      '': 'loadDefault',
      'search/results': 'showSearchResults'
    };
  }

  initialize() {
    window.console.log('Router initialized');
    this.listenTo(dispatcher, 'router:go', this.go);
  }

  go(route) {
    this.navigate(route, {trigger: true});
  }

  loadDefault() {
    new SearchBoxView();
  }

  showSearchResults() {
    new SearchResultsView();
  }

}

export default AppRouter;

Add shortcut function to navigate to URL fragment

Called by event listener


'use strict';

var bunyan = require('bunyan');
var Source = require('../node/nodes/source');

function AnalysisLogger(stream, user) {
    this.logger = bunyan.createLogger({
        name: 'camshaft',
        streams: [{
            level: 'info',
            stream: stream  || process.stdout
        }]
    });
    this.user = user;
}

module.exports = AnalysisLogger;

AnalysisLogger.prototype.log = function (analysis) {
    var self = this;

    analysis.getSortedNodes()
        .forEach(function (node) {
            if (node.getType() !== Source.TYPE) {
                self.logger.info({
                    analysis: analysis.id(),
                    node: node.id(),
                    type: node.getType(),
                    queued: node.didQueueWork(),
                    username: self.user
                }, 'analysis:node');
            }
        });
};

AnalysisLogger.prototype.logLimitsError = function (err) {
    if (err) {
        this.logger.info({ 'error-message': err.message, 'error-code': err.code }, 'analysis:limits_error');
    }
};

'use strict';

var bunyan = require('bunyan');
var Source = require('../node/nodes/source');

function AnalysisLogger(stream, user) {
    this.logger = bunyan.createLogger({
        name: 'camshaft',
        streams: [{
            level: 'info',
            stream: stream || process.stdout
        }]
    });
    this.user = user;

    // TODO: be able to configure the event and its convenience
    process.on('SIGHUP', () => this.reopenFileStreams());
}

module.exports = AnalysisLogger;

AnalysisLogger.prototype.log = function (analysis) {
    var self = this;

    analysis.getSortedNodes()
        .forEach(function (node) {
            if (node.getType() !== Source.TYPE) {
                self.logger.info({
                    analysis: analysis.id(),
                    node: node.id(),
                    type: node.getType(),
                    queued: node.didQueueWork(),
                    username: self.user
                }, 'analysis:node');
            }
        });
};

AnalysisLogger.prototype.logLimitsError = function (err) {
    if (err) {
        this.logger.info({ 'error-message': err.message, 'error-code': err.code }, 'analysis:limits_error');
    }
};

AnalysisLogger.prototype.reopenFileStreams () {
    this.logger.reopenFileStreams();
};

Fix "Uncaught exception: Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed"


/**
 * Internal dependencies
 */
import { wpApiFetch } from './wp-api-fetch';

const defaultSettings = {
	accountID: 100,
	propertyID: 200,
	profileID: 300,
	internalWebPropertyID: 400,
	useSnippet: true,
	// ampClientIDOptIn: (bool)
};

/**
 * Activate and set up the Analytics module.
 * @param {Object} settingsOverrides Optional settings to override the defaults.
 */
export async function setupAnalytics( settingsOverrides = {} ) {
	const settings = {
		...defaultSettings,
		...settingsOverrides,
	};
	// Activate the module.
	await wpApiFetch( {
		method: 'post',
		path: 'google-site-kit/v1/modules/analytics',
		data: { active: true },
	} );
	// Set dummy connection data.
	await wpApiFetch( {
		method: 'post',
		path: 'google-site-kit/v1/modules/analytics/data/settings',
		data: {
			data: settings,
		},
		parse: false,
	} );
}

/**
 * Internal dependencies
 */
import { wpApiFetch } from './wp-api-fetch';

const defaultSettings = {
	accountID: 100,
	propertyID: 200,
	profileID: 300,
	internalWebPropertyID: 400,
	useSnippet: true,
};

/**
 * Activate and set up the Analytics module.
 * @param {Object} settingsOverrides Optional settings to override the defaults.
 */
export async function setupAnalytics( settingsOverrides = {} ) {
	const settings = {
		...defaultSettings,
		...settingsOverrides,
	};
	// Activate the module.
	await wpApiFetch( {
		method: 'post',
		path: 'google-site-kit/v1/modules/analytics',
		data: { active: true },
	} );
	// Set dummy connection data.
	await wpApiFetch( {
		method: 'post',
		path: 'google-site-kit/v1/modules/analytics/data/settings',
		data: {
			data: settings,
		},
		parse: false,
	} );
}

Remove reference to ampClientIDOptIn in setupAnalytics utility.


'use strict';

/**
 * @ngdoc service
 * @name vegalite-ui.logger
 * @description
 * # logger
 * Service in the vegalite-ui.
 */
angular.module('vleApp')
  .service('Logger', function (localStorageService, consts) {

    var service = {};

    var timeStamp = function() {
      var now = new Date();
      var date = [ now.getFullYear(), now.getMonth() + 1, now.getDate()];
      var time = [ now.getHours(), now.getMinutes(), now.getSeconds() ];
      for ( var i = 1; i < 3; i++ ) {
        if ( time[i] < 10 ) {
          time[i] = "0" + time[i];
        }
      }
      return date.join("-") + " " + time.join(":");
    }

    service.logInteraction = function(action) {
      if (!consts.logging)
        return;
      var key = timeStamp();
      localStorageService.set(key, action);
    }

    service.clear = function() {
      localStorageService.clearAll();
    }

    return service;
  });

'use strict';

/**
 * @ngdoc service
 * @name vegalite-ui.logger
 * @description
 * # logger
 * Service in the vegalite-ui.
 */
angular.module('vleApp')
  .service('Logger', function (localStorageService, consts) {

    var service = {};

    // to avoid key collisions
    var previous;
    var counter = 0;

    var timeStamp = function() {
      var now = new Date();
      var date = [ now.getFullYear(), now.getMonth() + 1, now.getDate()];
      var time = [ now.getHours(), now.getMinutes(), now.getSeconds() ];
      for ( var i = 1; i < 3; i++ ) {
        if ( time[i] < 10 ) {
          time[i] = "0" + time[i];
        }
      }
      return date.join("-") + " " + time.join(":");
    }

    service.logInteraction = function(action) {
      if (!consts.logging)
        return;
      var key = timeStamp();

      if (key === previous) {
        key += " " + (++counter);
      } else {
        counter = 0;
        previous = key;
      }
      localStorageService.set(key, action);
    }

    service.clear = function() {
      localStorageService.clearAll();
    }

    return service;
  });

Fix key collisions in interaction logger


import Reflux from 'reflux';
import _ from 'lodash';

import { CheckListStoreMixin, HostingMixin, WaitForStoreMixin, StoreLoadingMixin } from '../../mixins';

import SessionActions from '../Session/SessionActions';
import Actions from './HostingActions';

export default Reflux.createStore({
  listenables: Actions,

  mixins: [
    CheckListStoreMixin,
    HostingMixin,
    WaitForStoreMixin,
    StoreLoadingMixin
  ],

  getInitialState() {
    return {
      items: [],
      isLoading: false
    };
  },

  init() {
    this.data = this.getInitialState();
    this.waitFor(
      SessionActions.setInstance,
      this.refreshData
    );
    this.setLoadingStates();
  },

  sendHostingAnalytics(type, payload) {
    window.analytics.track('Used Dashboard Sockets API', {
      type,
      instance: payload.instanceName,
      socketId: payload.label,
      socket: 'hosting'
    });
  },

  setHosting(data) {
    this.data.items = _.forEach(data, this.prepareHosting);
    this.trigger(this.data);
  },

  refreshData() {
    Actions.fetchHostings();
  },

  onFetchHostingsCompleted(data) {
    Actions.setHosting(data);
  },

  onCreateHostingCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('add', payload);
  },

  onUpdateHostingCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('edit', payload);
  },

  onRemoveHostingsCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('delete', payload);
  }
});

import Reflux from 'reflux';
import _ from 'lodash';

import { CheckListStoreMixin, HostingMixin, WaitForStoreMixin, StoreLoadingMixin } from '../../mixins';

import SessionActions from '../Session/SessionActions';
import Actions from './HostingActions';

export default Reflux.createStore({
  listenables: Actions,

  mixins: [
    CheckListStoreMixin,
    HostingMixin,
    WaitForStoreMixin,
    StoreLoadingMixin
  ],

  getInitialState() {
    return {
      items: [],
      isLoading: false
    };
  },

  init() {
    this.data = this.getInitialState();
    this.waitFor(
      SessionActions.setInstance,
      this.refreshData
    );
    this.setLoadingStates();
  },

  sendHostingAnalytics(type, payload) {
    window.analytics.track('Used Dashboard Sockets API', {
      type,
      instance: payload.instanceName,
      socketId: payload.label,
      socket: 'hosting'
    });
  },

  setHosting(data) {
    this.data.items = _.forEach(data, this.prepareHosting);
    this.trigger(this.data);
  },

  refreshData() {
    Actions.fetchHostings();
  },

  onFetchHostingsCompleted(data) {
    Actions.setHosting(data);
  },

  onCreateHostingCompleted(payload) {
    this.sendHostingAnalytics('add', payload);
    this.refreshData();
  },

  onUpdateHostingCompleted(payload) {
    this.sendHostingAnalytics('edit', payload);
    this.refreshData();
  },

  onRemoveHostingsCompleted(payload) {
    this.sendHostingAnalytics('delete', payload);
    this.refreshData();
  }
});

[DASH-2397] Move refreshData to the bottom of the method


module.exports = {
  lrc_notfound: '抱歉, 没找到歌词',
  account_missing: '请先设置豆瓣账户再操作: $ douban.fm config',
  setup_fail: '啊哦，启动出错了，请检查配置文件 ~/.douban.fm.profile.json',
  love_fail: '未知曲目无法加心',
  normal: '出错了, 请稍后再试...',
  last_song: '这是最后一首了哦，回车以加载最新列表',
  turn_to_local_mode: '获取豆瓣电台频道出错，切换为本地电台...',
  mkdir_fail: '创建歌曲文件夹出错，请检查权限',
  localsongs_notfound: '没有找到本地音乐'
};

exports default {
  'lrc_notfound': '抱歉, 没找到歌词',
  'account_missing': '请先设置豆瓣账户再操作: $ douban.fm config',
  'setup_fail': '啊哦，启动出错了，请检查配置文件 ~/.douban.fm.profile.json',
  'love_fail': '未知曲目无法加心',
  'normal': '出错了, 请稍后再试...',
  'last_song': '这是最后一首了哦，回车以加载最新列表',
  'turn_to_local_mode': '获取豆瓣电台频道出错，切换为本地电台...',
  'mkdir_fail': '创建歌曲文件夹出错，请检查权限',
  'localsongs_notfound': '没有找到本地音乐'
}

Rewrite lib error with ES6

Rewrite lib error with ES6


import configJson from '../../../../config.json'; // root path json config

const config = 'production' === process.env.NODE_ENV ? configJson.production : configJson.development;

export const GOOGLE_API_KEY = config.google && config.google.apiKey;
export const GOOGLE_CLIENT_ID = config.google && config.google.clientID
export const DROPBOX_APP_KEY = config.dropbox && config.dropbox.appKey

export const domain = config.domain;
export const urlpath = config.urlpath;
export const debug = config.debug;

export const port = window.location.port;
export const serverurl = `${window.location.protocol}//${domain ? domain : window.location.hostname}${port ? ':' + port : ''}${urlpath ? '/' + urlpath : ''}`;
window.serverurl = serverurl;
export const noteid = urlpath ? window.location.pathname.slice(urlpath.length + 1, window.location.pathname.length).split('/')[1] : window.location.pathname.split('/')[1];
export const noteurl = `${serverurl}/${noteid}`;

export const version = '0.5.0';

import configJson from '../../../../config.json'; // root path json config

const config = 'production' === process.env.NODE_ENV ? configJson.production : configJson.development;

export const GOOGLE_API_KEY = (config.google && config.google.apiKey) || '';
export const GOOGLE_CLIENT_ID = (config.google && config.google.clientID) || '';
export const DROPBOX_APP_KEY = (config.dropbox && config.dropbox.appKey) || '';

export const domain = config.domain || ''; // domain name
export const urlpath = config.urlpath || ''; // sub url path, like: www.example.com/<urlpath>
export const debug = config.debug || false;

export const port = window.location.port;
export const serverurl = `${window.location.protocol}//${domain ? domain : window.location.hostname}${port ? ':' + port : ''}${urlpath ? '/' + urlpath : ''}`;
window.serverurl = serverurl;
export const noteid = urlpath ? window.location.pathname.slice(urlpath.length + 1, window.location.pathname.length).split('/')[1] : window.location.pathname.split('/')[1];
export const noteurl = `${serverurl}/${noteid}`;

export const version = '0.5.0';

Add default value for config

Add default value for config


self.addEventListener('push', function(event) {
  event.waitUntil(self.registration.showNotification('ServiceWorker Cookbook', {
    body: 'Alea iacta est',
    tag: 'push',
  }));
});

self.addEventListener('push', function(event) {
  event.waitUntil(self.registration.showNotification('ServiceWorker Cookbook', {
    body: 'Alea iacta est',
  }));
});

Remove tag since it isn't useful for this recipe


import { timeAgoInWords, safe } from 'travis/utils/helpers';
import Ember from "ember";

export default Ember.Helper.helper(function(params) {
  return safe(moment(params[0]).format('MMMM D, YYYY H:mm:ss') || '-');
});

import { timeAgoInWords, safe } from 'travis/utils/helpers';
import Ember from "ember";

export default Ember.Helper.helper(function(params) {
  let date = new Date(params[0]);
  return safe(moment(date).format('MMMM D, YYYY H:mm:ss') || '-');
});

Remove moment deprecation on builds page

See https://github.com/moment/moment/issues/1407 for more details. All that was needed was to manually instantiate a new Date() object


var <%= scriptAppName %> = require('./<%= scriptAppName %>');
var React = require('react');
var {DefaultRoute, Route, Routes} = require('react-router');

React.renderComponent((
  <Routes location="history">
    <Route path="/" handler={<%= scriptAppName %>}>
    </Route>
  </Routes>
), document.getElementById('content'));

var <%= scriptAppName %> = require('./<%= scriptAppName %>');
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;

var content = document.getElementById('content');

var Routes = (
  <Route handler={<%= scriptAppName %>}>
    <Route name="/" handler={<%= scriptAppName %>}/>
  </Route>
);

Router.run(Routes, function (Handler) {
  React.render(<Handler/>, content);
});

Fix React Router after upgrade

Fix React Router after upgrade


const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const guildSchema = Schema({
	id: {type: String, unique: true, required: true},
	guildName: {type: String, required: true},
	icon: {type: String, default: null},
	commandPrefix: {type: String, default: '$', maxlength: 3},
	customStickers: [{
		name: {type: String, required: true, maxlength: 20},
		url: {type: String, required: true},
		uses: {type: Number, default: 0},
		creatorId: {type: String, required: true, default: 'unknown'},
		createdAt: {type: Date, default: Date.now},
		createdVia: {type: String, required: true, default: 'unknown'},
		groupType: {type: String, required: true, default: 'guild'},
		groupId: {type: String, required: true, default: 'unknown'}

	}],
	recentStickers: [String],
	stickerPacks: [String],
	guildManagerIds: [String],
	stickerManagerRole: {type: String, default: '@everyone', maxlength: 30},
	stickerManagerIds: [String],
	isActive: {type: Boolean, default: true}
});

let Guild = mongoose.model('Guild', guildSchema);

module.exports = Guild;

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const guildSchema = Schema({
	id: {type: String, unique: true, required: true},
	guildName: {type: String, required: true},
	icon: {type: String, default: null},
	commandPrefix: {type: String, default: '$', maxlength: 3},
	customStickers: [{
		name: {type: String, required: true, maxlength: 20},
		url: {type: String, required: true},
		uses: {type: Number, default: 0},
		creatorId: {type: String, required: true, default: 'unknown'},
		createdAt: {type: Date, default: Date.now},
		createdVia: {type: String, required: true, default: 'unknown'},
		groupType: {type: String, required: true, default: 'guild'},
		groupId: {type: String, required: true, default: 'unknown'}

	}],
	recentStickers: [String],
	stickerPacks: [String],
	guildManagerIds: [String],
	stickerManagerRole: {type: String, required: true, default: '@everyone'},
	stickerManagerIds: [String],
	isActive: {type: Boolean, default: true}
});

let Guild = mongoose.model('Guild', guildSchema);

module.exports = Guild;

Remove unneeded maxlength attr from 'stickerManagerRole' field in Guild Model


import 'jqueryui/draggable-unpatched'
import 'jquery-ui-touch-punch'

import 'jqueryui/draggable-unpatched'

import 'jqueryui/mouse'
import 'jquery-ui-touch-punch'

Fix js on mobile login screen — again!

Fix js on mobile login screen — again!

Closes: CORE-3190

This time in a way that will still work when webpack minifies it.

There is some bug in webpack/minify in the prod build where
`jqueryui/mouse` was not loaded by the time `jquery-ui-touch-punch`
was loaded, even though right on the previous line it has
`jqueryui/draggable-unpatched` and that file has:
```
import $ from 'jquery'
import 'jqueryui/core'
import 'jqueryui/mouse'
import 'jqueryui/widget'
```

Right at the top of it.

Test plan:
* in a production webpack build (with minified js and stuff)
* go to /login/canvas on a mobile device
* click the “forgot password” link
* it should work

Change-Id: I7e5708ff270ea7102f65d53708768f5ba60d7595
Reviewed-on: https://gerrit.instructure.com/201294
Tested-by: Jenkins
Reviewed-by: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
QA-Review: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
Product-Review: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>


var logger = require('log4js').getLogger('APP_LOG');

function verifiyMessage(config, receiver, message, botname, sender, password) {

	//If miss message, return error message

	if (message === undefined || message === null) {

		return 'Bad Request: Missing message';
	}

	//If receiver not found, return error message

	if (config.get(receiver) === undefined) {

		return 'Bad Request: Wrong receiver name';
	}

	//If sender not found, return error message

	if (config.get(sender) === undefined) {

		return 'Bad Request: Sender not found';
	}

	//If bot not found, return error message

	if (config.get(botname) === undefined) {

		return 'Bad Request: Wrong bot name';
	}

	//If password missmatch, return error message

	if (password !== config.get(sender).password1 &&
		password !== config.get(sender).password2) {

		return 'Bad Request: Password not match';
	}

	//If there are not any error, return Success

	return 'Message verified';

}

module.exports = {
	'verifiyMessage': verifiyMessage
};

var logger = require('log4js').getLogger('APP_LOG');

function verifiyMessage(config, receiver, message, botname, sender, password) {

	//If miss message, return error message

	if (message === undefined || message === null) {

		return 'Bad Request: Missing message';
	}

	//If receiver not found, return error message

	if (config.receivers[receiver] === undefined) {

		return 'Bad Request: Wrong receiver name';
	}

	//If sender not found, return error message

	if (config.senders[sender] === undefined) {

		return 'Bad Request: Sender not found';
	}

	//If bot not found, return error message

	if (config.bots[botname] === undefined) {

		return 'Bad Request: Wrong bot name';
	}

	//If password missmatch, return error message

	if (password !== config.senders[sender].password1 &&
		password !== config.senders[sender].password2) {

		return 'Bad Request: Password not match';
	}

	//If there are not any error, return Success

	return 'Message verified';

}

module.exports = {
	'verifiyMessage': verifiyMessage
};

Change solution of get config from config file


/**
 * Created by Fonov Sergei on 23.12.16.
 */

'use strict'

const req = require('tiny_request')

function sendreq(name, jsonData){
    return new Promise((resolve, reject) => {
        req.post({ url: this._url+name, jsonData: jsonData, json: true}, function(body, response, err){
            if (!err && response.statusCode == 200 && body.ok) {
                resolve(body.result)
            }else {
                console.log(`Error on method ${name}: ${body.error}`)
                reject(body.error)
            }
        })
    })
}

module.exports = sendreq

/**
 * Created by Fonov Sergei on 23.12.16.
 */

'use strict'

const req = require('tiny_request')

function sendreq(name, jsonData){
    return new Promise((resolve, reject) => {
        req.post({ url: this._url+name, jsonData: jsonData, json: true}, function(body, response, err){
            if (!err && response.statusCode == 200 && body.ok) {
                resolve(body.result)
            } else if (body) {
                console.log(`Error on method ${name}: ${body.error}`)
                reject(body.error)
            } else {
                reject(err)
            }
        })
    })
}

module.exports = sendreq

Fix Cannot read property 'error' of undefined


/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @format
 */

// The versions here are used across the documentation
// To use it in normal mdx, you can import this file and use a variable e.g. {site.lithoVersion}
// To use it in codeblocks, use the component in /docs/component/versionedCodeBlock.js,
// and refer to the version as: e.g. {{site.lithoVersion}}

export const site = {
  lithoVersion: '0.41.2',
  lithoSnapshotVersion: '0.41.3-SNAPSHOT',
  soloaderVersion: '0.9.0',
  flipperVersion: '0.46.0',
};

/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @format
 */

// The versions here are used across the documentation
// To use it in normal mdx, you can import this file and use a variable e.g. {site.lithoVersion}
// To use it in codeblocks, use the component in /docs/component/versionedCodeBlock.js,
// and refer to the version as: e.g. {{site.lithoVersion}}

export const site = {
  lithoVersion: '0.41.2',
  lithoSnapshotVersion: '0.41.3-SNAPSHOT',
  soloaderVersion: '0.10.4',
  flipperVersion: '0.46.0',
};

Bump SoLoader version to 0.10.4

Bump SoLoader version to 0.10.4

Reviewed By: adityasharat

Differential Revision: D37988573

fbshipit-source-id: 8e3569a3cce95c23295678fc78c7d5179d9779e5


(function($) {

	var notificationBar = {
    open: function(barId, barCloseId, cookie) {
      $('#' + barId).slideDown();

      $('#' + barCloseId).on('click', function() {
        notificationBar.close(barId, cookie);
      });
    },
    close: function(barId, cookie) {
      $('#' + barId).slideUp();
      $.cookie(cookie, true, { path: '/' });
    },
    reset: function(cookie) {
      $.removeCookie(cookie, { path: '/' });
    },
    setup: function(barId, barCloseId, cookie, func) {
      if (func()) this.open(barId, barCloseId, cookie);
    }
  };

  $('#reset-cookiebar').click(function() {
    notificationBar.reset('seen-cookie-notice');
  });

  notificationBar.setup('cookie', 'cookie-hide', 'seen-cookie-notice', function() {
    return !$.cookie('seen-cookie-notice');
  });
  notificationBar.setup('incompability', 'incompability-hide', 'seen-incompability-notice', function() {
    return $('html').is('.lt-ie8');
  });

})(jQuery);

(function($) {

	var notificationBar = {
    open: function(barId, barCloseId, cookie) {
      $('#' + barId).slideDown();

      $('#' + barCloseId).on('click', function() {
        notificationBar.close(barId, cookie);
      });
    },
    close: function(barId, cookie) {
      $('#' + barId).slideUp();
      $.cookie(cookie, true, { path: '/', expires: 365 });
    },
    reset: function(cookie) {
      $.removeCookie(cookie, { path: '/' });
    },
    setup: function(barId, barCloseId, cookie, func) {
      if (func()) this.open(barId, barCloseId, cookie);
    }
  };

  $('#reset-cookiebar').click(function() {
    notificationBar.reset('seen-cookie-notice');
  });

  notificationBar.setup('cookie', 'cookie-hide', 'seen-cookie-notice', function() {
    return !$.cookie('seen-cookie-notice');
  });
  notificationBar.setup('incompability', 'incompability-hide', 'seen-incompability-notice', function() {
    return $('html').is('.lt-ie8');
  });

})(jQuery);

Set cookie expiration to 365 days (was session)


LoginController.$inject = ['$rootScope', '$location', 'auth',
                                'role', 'toaster', 'TbUtils'];

function LoginController ($rootScope, $location, auth, role, toaster, TbUtils) {
    var vm = this;

    vm.username = "";
    vm.password = "";
    vm.login = login;
    vm.loading = false;

    auth.ClearCredentials();

    function login() {
        vm.loading = true;

        auth.Login( vm.username, vm.password, LoginSuccess, LoginFail);
    }

    function LoginSuccess(response) {
        console.log(response);
        auth.SetCredentials(response.data);

        window.localStorage['Session'] =
        $rootScope.Session =
        vm.username;

        window.localStorage['Username'] =
        $rootScope.Username =
        $rootScope.Session.slice(0, $rootScope.Session.indexOf('@'));

        role.get($rootScope.Session, getRoleSuccess);
    }

    function getRoleSuccess (response) {
        window.localStorage['Role'] =
        $rootScope.Role =
        response.data;

        $location.path('/proyectos');
        vm.loading = false;
    }

    function LoginFail(response) {
        console.log(response);
        TbUtils.showErrorMessage('error', response,
                                 'La cuenta ingresada no tiene privilegios de acceso',
                                 'Falla autorizacion');

        vm.loading = false;
    }
}

module.exports = { name: 'LoginController', ctrl: LoginController };

LoginController.$inject = ['$rootScope', '$location', 'auth',
                                'role', 'toaster', 'TbUtils'];

function LoginController ($rootScope, $location, auth, role, toaster, TbUtils) {
    var vm = this;

    vm.username = "";
    vm.password = "";
    vm.login = login;
    vm.loading = false;

    auth.ClearCredentials();

    function login() {
        vm.loading = true;

        auth.Login( vm.username, vm.password, LoginSuccess, LoginFail);
    }

    function LoginSuccess(response) {
        console.log(response);
        auth.SetCredentials(response.data.Token);

        window.localStorage['Session'] =
        $rootScope.Session =
        vm.username;

        window.localStorage['Username'] =
        $rootScope.Username =
        $rootScope.Session.slice(0, $rootScope.Session.indexOf('@'));

        role.get($rootScope.Session, getRoleSuccess);
    }

    function getRoleSuccess (response) {
        window.localStorage['Role'] =
        $rootScope.Role =
        response.data;

        $location.path('/proyectos');
        vm.loading = false;
    }

    function LoginFail(response) {
        console.log(response);
        TbUtils.showErrorMessage('error', response,
                                 'La cuenta ingresada no tiene privilegios de acceso',
                                 'Falla autorizacion');

        vm.loading = false;
    }
}

module.exports = { name: 'LoginController', ctrl: LoginController };

Fix login issue with token

Fix login issue with token


'use strict';

var codex = require('../codex');
var Boom = require('boom');
var Dashboard = require('../models/Dashboard');

module.exports = codex.controller(Dashboard, {
  get: true,
  search: true,
  insert: true,
  replace: true,
  preInsert: function (req, esRequest, callback) {
    if (!req.user || !req.user.isAdmin()) {
      return callback(Boom.forbidden());
    }

    // enforce unique constraint on name
    Dashboard.search({
      body: {
        query: {
          'constant_score': {
            filter: {
              term: {
                // use un-analyzed version of the field for case-sensitive matching
                'name': esRequest.body.name
              }
            }
          }
        }
      }
    }, function (err, results) {
      if (err) {
        return callback(err);
      }

      if (results.length > 0 && results[0]._.id !== esRequest.id) {
        return callback(Boom.create(400, 'There\'s already a dashboard with the name ' + esRequest.body.name, {
          error: 'UniqueConstraintViolation',
          field: 'name',
          value: esRequest.body.name
        }));
      }

      callback(null, esRequest);
    });
  },
  delete: true,
  preDelete: function (req, esRequest, callback) {
    if (!req.user || !req.user.isAdmin()) {
      return callback(Boom.forbidden());
    }

    callback(null, esRequest);
  }
}).with(require('../caper-trail').controller);

'use strict';

var codex = require('../codex');
var Boom = require('boom');
var Dashboard = require('../models/Dashboard');

module.exports = codex.controller(Dashboard, {
  get: true,
  search: true,
  insert: true,
  replace: true,
  preInsert: function (req, esRequest, callback) {
    if (!req.user || !req.user.isAdmin()) {
      return callback(Boom.forbidden());
    }

    // enforce unique constraint on name TODO this should be done in model
    Dashboard.search({
      body: {
        query: {
          'constant_score': {
            filter: {
              term: {
                // use un-analyzed version of the field for case-sensitive matching
                'name': esRequest.body.name
              }
            }
          }
        }
      }
    }, function (err, results) {
      if (err) {
        return callback(err);
      }

      if (results.length > 0 && results[0].id !== esRequest.id) {
        return callback(Boom.create(400, 'There\'s already a dashboard with the name ' + esRequest.body.name, {
          error: 'UniqueConstraintViolation',
          field: 'name',
          value: esRequest.body.name
        }));
      }

      callback(null, esRequest);
    });
  },
  delete: true,
  preDelete: function (req, esRequest, callback) {
    if (!req.user || !req.user.isAdmin()) {
      return callback(Boom.forbidden());
    }

    callback(null, esRequest);
  }
}).with(require('../caper-trail').controller);

Fix exception when saving dashboards

Fix exception when saving dashboards


'use strict';

var gulp = require('gulp'),
    jshint = require('gulp-jshint'),
    karma = require('karma').server;

var KARMA_CONFIG = '/karma.conf.js';

gulp.task('lint', function () {
    gulp.src('scripts/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});

gulp.task('test', function (done) {
    karma.start({
        configFile: __dirname + KARMA_CONFIG,
        singleRun: false
    }, done);
});

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

'use strict';

var gulp = require('gulp'),
    jshint = require('gulp-jshint'),
    karma = require('karma').server;

var KARMA_CONFIG = '/karma.conf.js';

gulp.task('lint', function () {
    gulp.src('scripts/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});

gulp.task('test', function (done) {
    karma.start({
        configFile: __dirname + KARMA_CONFIG,
        singleRun: false
    }, function () {
    	gulp.start('test');
    });
});

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

Fix gulp exit process with test

Fix gulp exit process with test


/*
 * index.js: Top-level include for the pkgcloud common module.
 *
 * (C) 2011 Nodejitsu Inc.
 *
 */

exports.auth = require('./auth');

[dist] Add top-level include for `pkgcloud.common`


const stack = require('../stack');
const evaluate = require('../evaluate');
const stdlib = require('../../stdlib');
const parse = require('../../parser/parse');

class BaseRuntime {
  constructor() {
    this.stack = stack();
    this.lexicon = stdlib;
  }

  loadWords(words) {
    this.lexicon = Object.assign(this.lexicon, words);
  }

  reset() {
    this.stack.unstack();
    this.lexicon = stdlib;
  }

  evaluate(source) {
    const ast = parse(source);
    evaluate(ast, this);
  }
}

module.exports = BaseRuntime;

const stack = require('../stack');
const evaluate = require('../evaluate');
const stdlib = require('../../stdlib');
const parse = require('../../parser/parse');

class BaseRuntime {
  constructor() {
    this.stack = stack();
    this.lexicon = stdlib;
  }

  loadWords(words) {
    this.lexicon = Object.assign(this.lexicon, words);
  }

  reset() {
    this.stack.unstack();
    this.lexicon = stdlib;
  }

  evaluate(source) {
    const ast = parse(source);

    if(ast == null) {
      throw new Error('Parse error!');
    }

    evaluate(ast, this);
  }
}

module.exports = BaseRuntime;

Add a condition to throw parse error on empty AST


/* See license.txt for terms of usage */

"use strict";

module.metadata = {
  "stability": "experimental"
};

const { Cu, Ci } = require("chrome");
const { Trace, TraceError } = require("../core/trace.js").get(module.id);
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { MarkupView } = devtools["require"]("devtools/markupview/markup-view");

// Patching MarkupView
// xxxHonza: Bug 1036949 - New API: MarkupView customization
let originalTemplate = MarkupView.prototype.template;
MarkupView.prototype.template = function(aName, aDest, aOptions) {
  let node = originalTemplate.apply(this, arguments);
  this._inspector.emit("markupview-render", node, aName, aDest, aOptions);
  return node;
}

function shutdown() {
  MarkupView.prototype.template = originalTemplate;
}

// Exports from this module
exports.shutdown = shutdown;

/* See license.txt for terms of usage */

"use strict";

module.metadata = {
  "stability": "experimental"
};

const { Cu, Ci } = require("chrome");
const { Trace, TraceError } = require("../core/trace.js").get(module.id);
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { MarkupView } = devtools["require"]("devtools/markupview/markup-view");

// Patching MarkupView
// xxxHonza: Bug 1036949 - New API: MarkupView customization
let originalTemplate = MarkupView.prototype.template;
MarkupView.prototype.template = function(aName, aDest, aOptions) {
  let node = originalTemplate.apply(this, arguments);
  // Needs to be fixed on the platform
  //this._inspector.emit("markupview-render", node, aName, aDest, aOptions);
  return node;
}

function shutdown() {
  MarkupView.prototype.template = originalTemplate;
}

// Exports from this module
exports.shutdown = shutdown;

Disable the Inspector panel patch (needs to be fixed on the platform)


import Ember from 'ember';
// import $ from 'jquery';

export default Ember.Component.extend({
  expense: {
    sum: '',
    category: '',
    name: ''
  },
  currency: '£',
  expenseCategories: [
    'Charity',
    'Clothing',
    'Education',
    'Events',
    'Food',
    'Gifts',
    'Healthcare',
    'Household',
    'Leisure',
    'Hobbies',
    'Trasportation',
    'Utilities',
    'Vacation'
  ],

  errorMessagesSum: {
    emRequired: 'This field can\'t be blank',
    emPattern: 'Must be a number!'
  },

  errorMessagesCategory: {
    emRequired: 'Select or add your own category'
  },

  init () {
    this._super();
    Ember.TextSupport.reopen({
      attributeBindings: ['em-required', 'em-min', 'em-max', 'em-pattern']
    });
  },

  didInsertElement () {
    componentHandler.upgradeAllRegistered();
  },

  actions: {
    clearInputs () {
      this.set('expense', {
        sum: '',
        category: '',
        name: ''
      });
      this.$('.mdl-textfield').removeClass('is-dirty is-invalid is-touched');
    },
    addExpense () {
      Ember.run.later(() => {
        if (!this.$().find('.is-invalid').length) {
          this.sendAction('action', this.get('expense'));
          this.send('clearInputs');
        }
      }, 200);
    }
  }
});

import Ember from 'ember';
// import $ from 'jquery';

export default Ember.Component.extend({
  expense: {
    sum: '',
    category: '',
    name: ''
  },
  currency: '£',
  expenseCategories: [
    'Charity',
    'Clothing',
    'Education',
    'Events',
    'Food',
    'Gifts',
    'Healthcare',
    'Household',
    'Leisure',
    'Hobbies',
    'Trasportation',
    'Utilities',
    'Vacation'
  ],

  errorMessagesSum: {
    emRequired: 'This field can\'t be blank',
    emPattern: 'Must be a number!'
  },

  errorMessagesCategory: {
    emRequired: 'Select or add your own category'
  },

  init () {
    this._super();
    Ember.TextSupport.reopen({
      attributeBindings: ['em-required', 'em-min', 'em-max', 'em-pattern']
    });
  },

  didInsertElement () {
    componentHandler.upgradeAllRegistered();
  },

  actions: {
    clearInputs () {
      this.set('expense', {
        sum: '',
        category: '',
        name: ''
      });
      this.$('.mdl-textfield').removeClass('is-dirty is-invalid is-touched');
    },
    addExpense () {
      Ember.run.later(() => {
        if (!this.$().find('.is-invalid').length) {
          let sum = this.get('expense').sum;
          this.set('expense.sum', parseFloat(sum).toFixed(2));
          this.sendAction('action', this.get('expense'));
          this.send('clearInputs');
        }
      }, 200);
    }
  }
});

refactor: Set expense to two decimals before saving it to db


import { autoUpdater } from 'electron-updater';
import {
  ON_ACCEPT_UPDATE,
  SEND_GENERAL_ALERT
} from '../events';

export default function updater(win) {
  const platform = process.platform;
  if (process.env.NODE_ENV === 'development' || platform === 'linux') return;

  const log = require('electron-log');

  log.transports.file.level = 'info';
  autoUpdater.logger = log;

  autoUpdater.checkForUpdates();

  autoUpdater.on('update-available', () => {
    notify(SEND_GENERAL_ALERT, 'Update is available');
  });

  autoUpdater.on('update-downloaded', () => {
    notify(SEND_GENERAL_ALERT, 'Zen Focus will be updated after it restarts.');
  });

  win.on(ON_ACCEPT_UPDATE, () => {
    autoUpdater.quitAndInstall();
  });

  function notify(channel, message) {
    win.webContents.send(channel, message);
  }
}

import { autoUpdater } from 'electron-updater';
import {
  ON_ACCEPT_UPDATE,
  SEND_GENERAL_ALERT
} from '../events';

export default function updater(win) {
  const platform = process.platform;
  if (process.env.NODE_ENV === 'development' || platform === 'linux') return;

  const log = require('electron-log');

  log.transports.file.level = 'info';
  autoUpdater.logger = log;

  autoUpdater.checkForUpdates();

  autoUpdater.on('update-downloaded', () => {
    notify(SEND_GENERAL_ALERT, 'Zen Focus will be updated after it restarts.');
  });

  win.on(ON_ACCEPT_UPDATE, () => {
    autoUpdater.quitAndInstall();
  });

  function notify(channel, message) {
    win.webContents.send(channel, message);
  }
}

build: Remove autoupdate message when update is available


import error from './tools/error';

const assign = require('object-assign');
const map = require('1-liners/map');

export default (templateFunction) => {
  if (typeof templateFunction !== 'function') throw error(
    'Wrong value of `templateFunction`. We expected a function.'
  );

  return (data) => assign({}, data, {docs: map(
    (doc) => {
      const output = templateFunction(doc);

      if (typeof output === 'undefined') return doc;
      return assign({}, doc, {output: String(output)});
    },
    data.docs
  )});
};

import error from './tools/error';

const assign = require('object-assign');
const map = require('1-liners/map');

export default (templateFunction) => {
  if (typeof templateFunction !== 'function') throw error(
    'Wrong value of `templateFunction`. We expected a function.'
  );

  return (data) => assign({}, data, {docs: map(
    (doc) => {
      const output = templateFunction(doc);

      if (typeof output === 'undefined') return doc;
      return assign({}, doc, {
        output: (output != null ? String(output) : output)
      });
    },
    data.docs
  )});
};

Handle `null` and `undefined` output

Handle `null` and `undefined` output


import values from 'lodash/values';
import queryString from 'query-string';
import { UPDATE_PATH } from 'redux-simple-router';
import Immutable from 'seamless-immutable';

import types from 'constants/ActionTypes';
import { pickSupportedFilters } from 'utils/SearchUtils';

const initialState = Immutable({
  filters: {
    date: '',
    people: '',
    purpose: '',
    search: '',
  },
  results: [],
  searchDone: false,
  typeaheadSuggestions: [],
});

function searchReducer(state = initialState, action) {
  switch (action.type) {

    case types.API.SEARCH_RESULTS_GET_SUCCESS: {
      const results = Object.keys(action.payload.entities.resources);
      return state.merge({
        results,
        searchDone: true,
      });
    }

    case types.API.TYPEAHEAD_SUGGESTIONS_GET_SUCCESS: {
      const typeaheadSuggestions = values(action.payload.resource);
      return state.merge({ typeaheadSuggestions });
    }

    case types.UI.CHANGE_SEARCH_FILTERS: {
      const filters = pickSupportedFilters(action.payload);
      return state.merge({ filters }, { deep: true });
    }

    case types.UI.CLEAR_SEARCH_RESULTS: {
      return initialState;
    }

    case UPDATE_PATH: {
      const query = queryString.extract(action.path);
      const urlSearchFilters = pickSupportedFilters(queryString.parse(query));
      return state.merge({ filters: urlSearchFilters }, { deep: true });
    }

    default: {
      return state;
    }
  }
}

export default searchReducer;

import values from 'lodash/values';
import queryString from 'query-string';
import { UPDATE_PATH } from 'redux-simple-router';
import Immutable from 'seamless-immutable';

import types from 'constants/ActionTypes';
import { pickSupportedFilters } from 'utils/SearchUtils';

const initialState = Immutable({
  filters: {
    date: '',
    people: '',
    purpose: '',
    search: '',
  },
  results: [],
  searchDone: false,
  typeaheadSuggestions: [],
});

function searchReducer(state = initialState, action) {
  switch (action.type) {

    case types.API.SEARCH_RESULTS_GET_SUCCESS: {
      const results = Object.keys(action.payload.entities.resources || {});
      return state.merge({
        results,
        searchDone: true,
      });
    }

    case types.API.TYPEAHEAD_SUGGESTIONS_GET_SUCCESS: {
      const typeaheadSuggestions = values(action.payload.resource);
      return state.merge({ typeaheadSuggestions });
    }

    case types.UI.CHANGE_SEARCH_FILTERS: {
      const filters = pickSupportedFilters(action.payload);
      return state.merge({ filters }, { deep: true });
    }

    case types.UI.CLEAR_SEARCH_RESULTS: {
      return initialState;
    }

    case UPDATE_PATH: {
      const query = queryString.extract(action.path);
      const urlSearchFilters = pickSupportedFilters(queryString.parse(query));
      return state.merge({ filters: urlSearchFilters }, { deep: true });
    }

    default: {
      return state;
    }
  }
}

export default searchReducer;

Fix search reducer when no results are found


moj.Modules.AutocompleteWrapper = {
  init: function () {
    const list = document.querySelectorAll('.fx-autocomplete-wrapper select')
    if (!list.length) return
    this.Autocomplete(list)
  },

  Autocomplete: function (nodeList) {
    nodeList.forEach((node) => {
      return moj.Helpers.Autocomplete.new('#' + node.id, {
        showAllValues: true,
        autoselect: false,
        displayMenu: 'overlay'
      })
    })
  }
}

moj.Modules.AutocompleteWrapper = {
  init: function () {
    const list = document.querySelectorAll('.fx-autocomplete-wrapper select')
    if (!list.length) return
    this.Autocomplete(list)
  },

  Autocomplete: function (nodeList) {
    for (let i = 0; i < nodeList.length; i++) {
      const node = nodeList[i]
      moj.Helpers.Autocomplete.new('#' + node.id, {
        showAllValues: true,
        autoselect: false,
        displayMenu: 'overlay'
      })
    }
  }
}

Revert newer method to accommodate IE11

Revert newer method to accommodate IE11


//Write a function, deepEqual, that takes two values and returns true only if they are the same value or are objects with the same properties whose values are also equal when compared with a recursive call to deepEqual.

function deepEqual(x, y) {
	if (((typeof x == "object") && (x != null)) && ((typeof y == "object") && (y != null))) {

		var compareLength = function(x,y) {
			let lengthX = 0;
			let lengthY = 0;
			for (var prop in x) {
				lengthX++;
			}
			for (var prop in y) {
				lengthY++;
			}
			return (lengthX == lengthY);
		}

		if (compareLength(x,y) == false) {
			return false;
		}

		for (var prop in x) {
			if (prop in y) {
				if (deepEqual(x[prop], y[prop]) == false) {
					return false;
				}
			}
			else {
				return false;
			}
		}
		return true;
	}
return (x === y);
};

const obj = {here: {is: "an"}, object: 2};

console.log(deepEqual(obj, obj));
console.log(deepEqual(obj, {here: 1, object: 2}));
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));

//Write a function, deepEqual, that takes two values and returns true only if they are the same value or are objects with the same properties whose values are also equal when compared with a recursive call to deepEqual.

function deepEqual(x, y) {
    if (isObject(x) && isObject(y) && areSameLength(x, y)) {
        return Object.keys(x).every((key) => {
            return y.hasOwnProperty(key) ? deepEqual(x[key], y[key]) : false;
        });
    }
    return (x === y);
};

function isObject(value) {
    return typeof value === 'object' && value !== null;
}

function areSameLength(x, y) {
    let lengthX = 0;
    let lengthY = 0;
    for (let prop in x) {
        lengthX++;
    }
    for (let prop in y) {
        lengthY++;
    }
    return (lengthX === lengthY);
}

const obj = {here: {is: "an"}, object: 2};

console.log(deepEqual(obj, obj));
console.log(deepEqual(obj, {here: 1, object: 2}));
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));

Break out conditionals to helper functions

Use Object.keys and array.prototype.every to compare object
keys/properties


$(document).ready(function() {
  if ($("#fancy-particles").length) {
    particlesJS.load('fancy-particles', '_static/particles.json', null);
  }
});

Load particles after DOM finishes.

Load particles after DOM finishes.


'use strict';

(function() {

  angular.module('impactApp.auth')
    .run(function($rootScope, $state, Auth) {
      // Redirect to login if route requires auth and the user is not logged in, or doesn't have required role
      $rootScope.$on('$stateChangeStart', function(event, next, nextParams) {
        if (!next.authenticate) {
          return;
        }

        if (typeof next.redirectTo !== 'undefined') {
          event.preventDefault();
          if (typeof next.redirectTo === 'string') {

            $state.go(next.redirectTo, nextParams);
          } else {
            var params = _.assign(nextParams, next.redirectTo.params);
            $state.go(next.redirectTo.url, params);
          }

          return;
        }

        if (typeof next.authenticate === 'string') {
          Auth.hasRole(next.authenticate, _.noop).then(has => {
            if (has) {
              return;
            }

            event.preventDefault();
            return Auth.isLoggedIn(_.noop).then(is => {
              $state.go(is ? 'departement' : 'login');
            });
          });
        } else {
          Auth.isLoggedIn(_.noop).then(is => {
            if (is) {
              return;
            }

            event.preventDefault();
            $state.go('departement');
          });
        }
      });
    });
})();

'use strict';

(function() {

  angular.module('impactApp.auth')
    .run(function($rootScope, $state, Auth) {
      // Redirect to login if route requires auth and the user is not logged in, or doesn't have required role
      $rootScope.$on('$stateChangeStart', function(event, next, nextParams) {
        if (typeof next.authenticate !== 'undefined') {
          Auth.isLoggedIn(_.noop).then(is => {
            if (is) {
              return;
            }

            event.preventDefault();
            $state.go('login');
          });

          return;
        }

        if (typeof next.redirectTo !== 'undefined') {
          event.preventDefault();
          if (typeof next.redirectTo === 'string') {
            $state.go(next.redirectTo, nextParams);
          } else {
            var params = _.assign(nextParams, next.redirectTo.params);
            $state.go(next.redirectTo.url, params);
          }

          return;
        }
      });
    });
})();

Resolve redirectTo even if state doesn't need auth


import superagent from 'superagent/lib/client';

/**
 * Simple helper module to make HTTP requests.
 */
export default {
	get:  request.bind(null, superagent.get),
	put:  request.bind(null, superagent.put),
	del:  request.bind(null, superagent.del),
	post: request.bind(null, superagent.post)
}

/**
 * Simple helper function to make HTTP requests. Note that you don't call this
 * directly but instead use one of the pre-bound methods above.
 */
function request(to, options = {}) {
	return new Promise((resolve, reject) => {
		let request = to(options.url)
			.set('Accept',        'application/json')
			.set('Content-Type',  'application/json')
			.set('Authorization', `Bearer ${options.token}`);
		if(options.payload) {
			request = request.send(options.payload)
		}
		return request.end((err, res) => {
			if(err) {
				err.statusCode = err.status || res ? res.status : 0;
				return reject(err);
			}
			return resolve({ body: res.body, headers: res.headers });
		});
	});
}

import superagent from 'superagent/lib/client';
import page       from 'page';
/**
 * Simple helper module to make HTTP requests.
 */
export default {
	get:  request.bind(null, superagent.get),
	put:  request.bind(null, superagent.put),
	del:  request.bind(null, superagent.del),
	post: request.bind(null, superagent.post)
}

/**
 * Simple helper function to make HTTP requests. Note that you don't call this
 * directly but instead use one of the pre-bound methods above.a
 */
function request(to, options = {}) {
	return new Promise((resolve, reject) => {
		let request = to(options.url)
			.set('Accept',        'application/json')
			.set('Content-Type',  'application/json')
			.set('Authorization', `Bearer ${options.token}`);
		if(options.payload) {
			request = request.send(options.payload)
		}
		return request.end((err, res) => {
			if(err) {
				err.statusCode = err.status || res ? res.status : 0;
				console.log(err.statusCode);

				if (err.statusCode == 404) {
				 // Insert custom 404 redirect here
					page.redirect('/workspace');
				}

				else if (err.statusCode == 400) {
					page.redirect('/workspace');
				}
				return reject(err);
			}
			return resolve({ body: res.body, headers: res.headers });
		});
	});
}

Send user back to workspace if they try to access non-existent board


Teikei.Controller = Backbone.Marionette.Controller.extend({

  initialize: function(options){
  },

  index: function(){
    alert("Hello from Marionette Beta Controller");
  }

});

Teikei.Controller = Backbone.Marionette.Controller.extend({

  initialize: function(options){
  },

  index: function(){
  }

});

Remove debug alert from Marionette controller.


import {Controller} from "@hotwired/stimulus"

export default class extends Controller {

    static targets = ["link", "result"]

    initialize() {
        let options = {
            rootMargin: '100px',
        }

        this.intersectionObserver = new IntersectionObserver(entries => this.processIntersectionEntries(entries), options)
    }

    connect() {
        this.intersectionObserver.observe(this.linkTarget)
    }

    disconnect() {
        this.intersectionObserver.unobserve(this.linkTarget)
    }

    processIntersectionEntries(entries) {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                this.load()
            }
        })
    }

    loadFromClick(event) {
        event.preventDefault()
        this.load()
    }

    load() {
        const nextPageUrl = this.data.get("nextPageUrl")
        const htmlTemplate = this.data.get("htmlTemplate")
        const endOfListHtml = "
End of List
"

        if (nextPageUrl !== "null") {
            const url = nextPageUrl + "&html_template=" + htmlTemplate

            Rails.ajax({
                type: "GET",
                url: url,
                dataType: "json",
                success: (data) => {
                    this.data.set("nextPageUrl", data.links.next)
                    this.resultTarget.innerHTML += data.html
                    if (data.links.next === null) {
                        this.linkTarget.innerHTML = endOfListHtml
                    }
                }
            })
        } else {
            this.linkTarget.innerHTML = endOfListHtml
        }
    }
}

import {Controller} from "@hotwired/stimulus"

export default class extends Controller {

    static targets = ["link", "result"]

    initialize() {
        let options = {
            rootMargin: '100px',
        }

        this.intersectionObserver = new IntersectionObserver(entries => this.processIntersectionEntries(entries), options)
    }

    connect() {
        this.intersectionObserver.observe(this.linkTarget)
    }

    disconnect() {
        this.intersectionObserver.unobserve(this.linkTarget)
    }

    processIntersectionEntries(entries) {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                this.load()
            }
        })
    }

    loadFromClick(event) {
        event.preventDefault()
        this.load()
    }

    load() {
        const nextPageUrl = this.data.get("nextPageUrl")
        const htmlTemplate = this.data.get("htmlTemplate")
        const endOfListHtml = "
End of List
"

        if (!nextPageUrl || nextPageUrl.length === 0 || nextPageUrl === "null") {
            this.linkTarget.innerHTML = endOfListHtml
        } else {
            const url = nextPageUrl + "&html_template=" + htmlTemplate

            Rails.ajax({
                type: "GET",
                url: url,
                dataType: "json",
                success: (data) => {
                    this.data.set("nextPageUrl", data.links.next)
                    this.resultTarget.innerHTML += data.html
                    if (data.links.next === null) {
                        this.linkTarget.innerHTML = endOfListHtml
                    }
                }
            })
        }
    }
}

Make test for nextPageUrl more robust

Make test for nextPageUrl more robust


var fs = require('fs');

module.exports = function() {
  return fs.readdirSync('src/activities').map(function(dirName) {
    return {
      slug: dirName,
      fileName: './src/activities/' + dirName + '/config.json'
    };
  }).filter(function(activity) {
    return fs.statSync(activity.fileName).isFile();
  }).map(function(activity) {
    var metaDataJSON = String(fs.readFileSync(activity.fileName));
    var metaData = JSON.parse(metaDataJSON);
    metaData.slug = activity.slug;
    return metaData;
  });
};

var fs = require('fs');
var path = require('path');

var activitiesDir = path.join(__dirname, '../activities');

/**
 * Return an array with metadata for each activity as defined by the files
 * present in the project's `src/activities/` directory. Additionally, perform
 * some basic validation to ensure that each activity conforms to the
 * expectations of the build process.
 */
module.exports = function() {
  return fs.readdirSync(activitiesDir).map(function(name) {
    var directory = path.join(activitiesDir, name);
    return {
      slug: name,
      directory: directory,
      configFile: directory + '/config.json'
    };
  }).filter(function(activity) {
    return fs.statSync(activity.configFile).isFile();
  }).map(function(activity) {
    var configJSON = String(fs.readFileSync(activity.configFile));
    var config = JSON.parse(configJSON);
    try {
      validate(activity.directory, config);
    } catch(err) {
      err.message = 'Activity error: (' + activity.slug + ') '+ err.message;
      throw err;
    }
    config.slug = activity.slug;
    return config;
  });
};

function validate(directory, metaData) {
  if ('slug' in metaData) {
    throw new Error('The "slug" configuration parameter is reserved');
  }
  if (!fs.statSync(directory + '/client/scripts/main.js').isFile()) {
    throw new Error(
      'Missing "main.js" entry point in "client/scripts" directory'
    );
  }
}

Validate Activity data and structure

Validate Activity data and structure

Promote early discovery of errors in Activity defintions.


define(function(){'use strict';
return function(iterations = 1, ratio = 0.5, endValue = false){
  let sequence = [],
      currBlock = 1;
  for(var ii = 0; ii < ratio; ii++){
    sequence.push(currBlock);
      currBlock = currBlock * ratio;
  }
  if(endValue){ // Return only the last value
    return sequence.pop();
  }
  return sequence;
};
});

define(function(){'use strict';
return function(iterations, ratio, endValue){
  iterations = iterations || 1;
  ratio = ratio || 0.5;
  endValue = !!endValue;

  let sequence = [],
      currBlock = 1;

  for(var ii = 0; ii < iterations; ii++){
    sequence.push(currBlock);
      currBlock = currBlock * ratio;
  }
  if(endValue){ // Return only the last value
    return sequence.pop();
  }
  return sequence;
};
});

Fix for loop condition error

Fix for loop condition error

On line 10, compare to iterations not ratio


import Ember from 'ember';
import $ from 'jquery';

export default Ember.Component.extend({
  expense: {
    sum: null,
    category: '',
    name: ''
  },
  currency: '£',
  expenseCategories: [
    'Charity',
    'Clothing',
    'Education',
    'Events',
    'Food',
    'Gifts',
    'Healthcare',
    'Household',
    'Leisure',
    'Hobbies',
    'Trasportation',
    'Utilities',
    'Vacation'
  ],
  didInsertElement () {
    var dialog = document.getElementById(this.$().attr('id'));
    var showDialogButton = $('[dialog-open]');
    console.log(dialog, showDialogButton);
    if (!dialog.showModal) {
      dialogPolyfill.registerDialog(dialog);
    }
    showDialogButton.click(function () {
      dialog.showModal();
    });
    // dialog.querySelector('.close').addEventListener('click', function () {
    //   dialog.close();
    // });
    $(dialog).on('click', function () {
      dialog.close();
    });
    componentHandler.upgradeAllRegistered()
  }
});

import Ember from 'ember';
// import $ from 'jquery';

export default Ember.Component.extend({
  expense: {
    sum: null,
    category: '',
    name: ''
  },
  currency: '£',
  expenseCategories: [
    'Charity',
    'Clothing',
    'Education',
    'Events',
    'Food',
    'Gifts',
    'Healthcare',
    'Household',
    'Leisure',
    'Hobbies',
    'Trasportation',
    'Utilities',
    'Vacation'
  ],
  didInsertElement () {
    componentHandler.upgradeAllRegistered();
  },

  actions: {
    clearInputs () {
      this.$('.mdl-textfield input[type=text]').val('');
      this.$('.mdl-textfield').removeClass('is-dirty');
    },
    addExpense () {
      console.log(this.get('expense'));
    }
  }
});

Add actions for add expense form

feat: Add actions for add expense form


import React from 'react';
import { movePiece } from '../actions';
import { connect } from 'react-redux';
import _ from 'lodash';

const mapStateToProps = (state) => {
  return {
    board: state.board,
    turn: state.turn
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    onPieceClick: (board, piece) => {
      dispatch(movePiece(board, piece));
    }
  };
};

export default class ShogiPiece extends React.Component {
  render() {
    var pieceName = _.kebabCase(this.props.piece.constructor.name);
    var destination = this.props.piece.isBlack() ? 'up' : 'down';

    return(
      <span className={`${pieceName} ${destination}`} onClick={() => this.props.onPieceClick(this.props.board, this.props.piece)}>
        {this.props.piece.type}
      </span>
    );
  }
}

const Piece = connect(
  mapStateToProps,
  mapDispatchToProps
)(ShogiPiece);

export default Piece;

import React from 'react';
import { movePiece } from '../actions';
import { connect } from 'react-redux';
import _ from 'lodash';

const mapStateToProps = (state) => {
  return {
    board: state.board,
    turn: state.turn
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    onPieceClick: (board, piece) => {
      dispatch(movePiece(board, piece));
    }
  };
};

export default class ShogiPiece extends React.Component {
  render() {
    return(
      <img onClick={() => this.props.onPieceClick(this.props.board, this.props.piece)}>
      </img>
    );
  }
}

const Piece = connect(
  mapStateToProps,
  mapDispatchToProps
)(ShogiPiece);

export default Piece;

Use img tag instead of span tag.

Use img tag instead of span tag.


module.exports = function(server) {
  var fs  = require('fs')
    , mongoose  = require('mongoose')
    , options   = { autoReconnect: true }
    , mongodb   = server.config.mongodb
    , auth = ''
    , db
    ;

  /**
   * Set up mongodb.
   */
  if(mongodb.user)
    auth = mongodb.user+":"+mongodb.pass+"@";

  var mongourl = process.env.MONGOLAB_URI ||
    process.env.MONGOHQ_URL ||
    'mongodb://' + auth + mongodb.host + ':' + (mongodb.port || 27017) + '/' + mongodb.database;

  db = mongoose.createConnection(mongourl, options, function (err, db2) {
    if (err) console.error('MONGODB : ', err.message);
  });
  var eventHandler = db.db;

  eventHandler.on('open', function(err) {
    console.log('Mongoose connected.');
  });
  eventHandler.on('error', function(err) {
    console.error('MONGODB : ', err);
  });

  server.set('db', db);

  /**
   * Models.
   */
  server.mongoose = require('mongoose');

  var ms = {};
  var models = [
    'Game',
  ];

  server.model = (modelName) => {
    return server.set('db').model(modelName);
  };

  models.forEach(model => {
    ms[model] = require(`${__dirname}/${model.toLowerCase()}`)(server);
  });

  return ms;

};

module.exports = function(server) {
  var fs  = require('fs')
    , mongoose  = require('mongoose')
    , options   = { autoReconnect: true }
    , mongodb   = server.config.mongodb
    , auth = ''
    , db
    ;

  /**
   * Set up mongodb.
   */
  if(mongodb.user)
    auth = mongodb.user+":"+mongodb.pass+"@";

  var mongourl = process.env.MONGODB_URI ||
    'mongodb://' + auth + mongodb.host + ':' + (mongodb.port || 27017) + '/' + mongodb.database;

  db = mongoose.createConnection(mongourl, options, function (err, db2) {
    if (err) console.error('MONGODB : ', err.message);
  });
  var eventHandler = db.db;

  eventHandler.on('open', function(err) {
    console.log('Mongoose connected.');
  });
  eventHandler.on('error', function(err) {
    console.error('MONGODB : ', err);
  });

  server.set('db', db);

  /**
   * Models.
   */
  server.mongoose = require('mongoose');

  var ms = {};
  var models = [
    'Game',
  ];

  server.model = (modelName) => {
    return server.set('db').model(modelName);
  };

  models.forEach(model => {
    ms[model] = require(`${__dirname}/${model.toLowerCase()}`)(server);
  });

  return ms;

};

Fix mongodb uri from heroku

Fix mongodb uri from heroku


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);
    console.log("Route: ", this.routerService);
    var pathSuffix = params.rd || "";
    let url = config.apiUrl + '/oauth/provider?redirect=' + host + pathSuffix + "%3Ftoken%3D%7BgirderToken%7D";

    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) || "";
    // Append to query string if on exists, otherwise add one
    if (pathSuffix.indexOf("?") !== -1) {
      pathSuffix += "&token={girderToken}"
    } else {
      pathSuffix += "?token={girderToken}"
    }
    var redirectUrl = host + pathSuffix;
    let url = config.apiUrl + '/oauth/provider?redirect=' + encodeURIComponent(redirectUrl);

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

Append token to querystring parameter, when applicable


// use strict:
"use strict";

// Function gets the location of the user provided the user opts in
// function adapted from Sitepoint; https://www.sitepoint.com/html5-geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(userPosition, showError);
} else {
        alert('Geolocation is not supported in your browser so cannot display your local weather');
}

// Success callback function
function userPosition(position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
	console.log("User's latitude is " + lat + " User's longitude is " + lon);
    // return lat, lon; // how to return two vars?
}

// Error callback function
function showError(error) {
        switch(error.code) {
                case error.PERMISSION_DENIED:
                        alert("User denied the request for Geolocation.");
                        break;
                case error.POSITION_UNAVAILABLE:
                        alert("Location information is unavailable.");
                        break;
                case error.TIMEOUT:
                        alert("The request to get user location timed out.");
                        break;
                case error.UNKNOWN_ERROR:
                        alert("An unknown error occurred.");
                        break;
        }
}

// use strict:
"use strict";

// Function gets the location of the user provided the user opts in
// Function for geolocation, success and error adapted from Sitepoint;
// URL https://www.sitepoint.com/html5-geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(userPosition, showError);
} else {
        alert('Geolocation is not supported in your browser so cannot display your local weather');
}

// Success callback function
// Determine's user location and builds in latitude and longitude into the DarkSky API url
function userPosition(position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
	console.log("User's latitude is " + lat + " User's longitude is " + lon);

	// Next line builds the API url for DarkSky
	var darkSkyAPI = 'https://api.darksky.net/forecast/' + darkSkyToken + '/' + lat + ',' + lon;
    console.log(darkSkyAPI);
    return darkSkyAPI;
}

// Error callback function
function showError(error) {
        switch(error.code) {
                case error.PERMISSION_DENIED:
                        alert("User denied the request for Geolocation.");
                        break;
                case error.POSITION_UNAVAILABLE:
                        alert("Location information is unavailable.");
                        break;
                case error.TIMEOUT:
                        alert("The request to get user location timed out.");
                        break;
                case error.UNKNOWN_ERROR:
                        alert("An unknown error occurred.");
                        break;
        }
}

$.ajax({
      url: 'https://api.darksky.net/forecast/c9ef245f82717baa8be804cab471c6f2/51,0',
      type: "GET",
      dataType: "jsonp",
      success: function (weather) {
      	$('#temperature').prepend(weather.currently.temperature);
      	$('#weather-icon').append(weather.currently.icon);
  		// console.log(weather.currently.icon);

},
      xhrFields: {
    withCredentials: false
  }
    }) // end ajax

Change userPos func to build API url

refactor: Change userPos func to build API url


const objectAssign = require('object-assign')
const urlParse = require('url-parse')

export const processOptions = opts => {
  const options = objectAssign({}, opts)

  // Parse URL into parts
  const url = urlParse(
    options.url,
    {},  // Don't use current browser location
    true // Parse query strings
  )

  // Shallow-merge (override) existing query params
  if (options.query) {
    url.query = objectAssign({}, url.query, options.query)
  }

  // Implicit POST if we have not specified a method but have a body
  options.method = (options.body && !options.method)
    ? 'POST'
    : (options.method || 'GET').toUpperCase()

  // Stringify URL
  options.url = url.toString()

  return options
}

const objectAssign = require('object-assign')
const urlParse = require('url-parse')

export const processOptions = opts => {
  const options = typeof opts === 'string'
    ? {url: opts}
    : objectAssign({}, opts)

  // Parse URL into parts
  const url = urlParse(
    options.url,
    {},  // Don't use current browser location
    true // Parse query strings
  )

  // Shallow-merge (override) existing query params
  if (options.query) {
    url.query = objectAssign({}, url.query, options.query)
  }

  // Implicit POST if we have not specified a method but have a body
  options.method = (options.body && !options.method)
    ? 'POST'
    : (options.method || 'GET').toUpperCase()

  // Stringify URL
  options.url = url.toString()

  return options
}

Allow passing string instead of options object


var cc = cc || {};
var acg = acg || {};
acg.ext = acg.ext || {};

acg.ext._res_path = '.';
acg.ext.set_res_path = function (path) {
    if (path.endsWith('/')) path = path.substr(0, path.length - 1);
    acg.ext._res_path = path;
};

var cc = cc || {};
var acg = acg || {};
acg.ext = acg.ext || {};

acg.ext._res_path = '.';
acg.ext.set_res_path = function (path) {
    if (path.charAt(path.length - 1) === '/') path = path.substr(0, path.length - 1);
    acg.ext._res_path = path;
};

Improve compatibility (only Firefox supports string.endsWith)


/**
 * List function - use `start()` and `send()` to output headers and content.
 * @link http://docs.couchdb.org/en/latest/couchapp/ddocs.html#listfun
 *
 * @param {object} head - View Head Information. http://docs.couchdb.org/en/latest/json-structure.html#view-head-info-object
 * @param {object} req - Request Object. http://docs.couchdb.org/en/latest/json-structure.html#request-object
 **/
function(head, req) {
  start({
    'headers': {
      'Content-Type': 'text/html'
    }
  });
  send('');
  send('
');
  while (row = getRow()) {
    send('
');
    if (typeof(row.key) !== 'string') {
      for (var i = 0; i < row.key.length; i++) {
        send('' + row.key[i] + '	');
      }
      send('' + row.value + '	');
    }
    send('
');
  }
  send('
');
  send('');
}

/**
 * List function - use `start()` and `send()` to output headers and content.
 * @link http://docs.couchdb.org/en/latest/couchapp/ddocs.html#listfun
 *
 * @param {object} head - View Head Information. http://docs.couchdb.org/en/latest/json-structure.html#view-head-info-object
 * @param {object} req - Request Object. http://docs.couchdb.org/en/latest/json-structure.html#request-object
 **/
function(head, req) {
  var ddoc = this;
  start({
    'headers': {
      'Content-Type': 'text/html'
    }
  });
  send(ddoc.templates.header);
  send('

');
  send('
');
  while (row = getRow()) {
    send('
');
    if (typeof(row.key) !== 'string') {
      for (var i = 0; i < row.key.length; i++) {
        send('' + row.key[i] + '	');
      }
      send('' + row.value + '	');
    }
    send('
');
  }
  send('
');
  send('

');
  send(ddoc.templates.footer);
}

Update users list to match new styles & UI


var error = require('./requestHandlers/error.js');

module.exports = function(req, res, conditions) {
  var offset = req.query.offset
    , limit  = req.query.limit;

  if (!offset) {
    error.missingParam('offset', res);
    return false;
  } else if (!limit) {
    error.missingParam('limit', res);
    return false;
  }

  if (offset < 0) {
    error.badRequest('Offset parameter must be greater than or equal to zero', res);
    return false;
  }

  if (limit <= 0) {
    error.badRequest('Limit parameter must be greater than zero', res);
    return false;
  }

  conditions['skip']  = offset;
  conditions['limit'] = limit;

  return true;
};

var error = require('./requestHandlers/error.js');

module.exports = function(req, res, conditions) {
  var offset = req.query.offset
    , limit  = req.query.limit;

  if (!offset) {
    error.missingParam(res, 'offset');
    return false;
  } else if (!limit) {
    error.missingParam(res, 'limit');
    return false;
  }

  if (offset < 0) {
    error.badRequest(res, 'Offset parameter must be greater than or equal to zero');
    return false;
  }

  if (limit <= 0) {
    error.badRequest(res, 'Limit parameter must be greater than zero');
    return false;
  }

  conditions['skip']  = offset;
  conditions['limit'] = limit;

  return true;
};

Update pagination to use new order of err params


import { h } from 'hyperapp'

export const SettingsAbout = ({state}) =>

Turtle Control Software v{state.system_info.tcs_ver}

Firmware v{state.system_info.firmware_ver}

External WiFi: {state.system_info.wifi_dongle}

Video devices: {() => state.system_info.video_devices.toString()}

import { h } from 'hyperapp';

export const SettingsAbout = ({ state }) =>

Turtle Control Software v{state.system_info.tcs_ver}

Shield Firmware v{state.system_info.firmware_ver}

External WiFi: {state.system_info.wifi_dongle}

Video devices: {() => state.system_info.video_devices.toString()}

;

Add "Shield" to Firmware string

Add "Shield" to Firmware string


pageflow.retryable = {
  retry: function(options) {
    options = options ? _.clone(options) : {};
    if (options.parse === void 0) options.parse = true;
    var model = this;
    options.success = function(resp) {
      if (!model.set(model.parse(resp, options), options)) return false;
      model.trigger('sync', model, resp, options);
    };
    options.error = function(resp) {
      model.trigger('error', model, resp, options);
    };
    options.url = this.url() + '/retry';
    return this.sync('post', this, options);
  }
};

pageflow.retryable = {
  retry: function(options) {
    options = options ? _.clone(options) : {};
    if (options.parse === void 0) options.parse = true;
    var model = this;
    options.success = function(resp) {
      if (!model.set(model.parse(resp, options), options)) return false;
      model.trigger('sync', model, resp, options);
    };
    options.error = function(resp) {
      model.trigger('error', model, resp, options);
    };
    options.url = this.url() + '/retry';
    return this.sync('create', this, options);
  }
};

Use correct Backbone sync parameter to trigger retry

Former parameter caused a get request, which lead to a 404.


import React, { Component } from 'react';
import Dialog from 'material-ui/lib/dialog';
import FlatButton from 'material-ui/lib/flat-button';
import RaisedButton from 'material-ui/lib/raised-button';

// NOTE: For emit `onTouchTap` event.
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

export default class PromoteModal extends Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
  }

  closeModal() {
    this.props.onHidePromoteModal();
    this.setState({ open: this.props.open });
  }

  render() {
    const actions = [
      <FlatButton label="Cancel" primary={true} onTouchTap={this.handleClose.bind(this)} />,
      <FlatButton label="Submit" primary={true} onTouchTap={this.handleClose.bind(this)} />
    ];

    return (
      <div>
        <Dialog title="" actions={actions} modal={true} open={this.props.open} />
      </div>
    );
  }
}

import React, { Component } from 'react';
import Dialog from 'material-ui/lib/dialog';
import FlatButton from 'material-ui/lib/flat-button';
import RaisedButton from 'material-ui/lib/raised-button';

// NOTE: For emit `onTouchTap` event.
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

export default class PromoteModal extends Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
  }

  closeModal() {
    this.props.onHidePromoteModal();
  }

  render() {
    const actions = [
      <FlatButton label="Cancel" primary={true} onTouchTap={this.handleClose.bind(this)} />,
      <FlatButton label="Submit" primary={true} onTouchTap={this.handleClose.bind(this)} />
    ];

    return (
      <div>
        <Dialog title="" actions={actions} modal={true} open={this.props.open} />
      </div>
    );
  }
}

Remove `setState`, For hide modal, it is enough to call `onHidePromoteModal`.


/**
 * Test dependencies.
 *
 * This file lists out all of the individual spec (test) files so that they
 * are run by our infrastructure.
 */
// App configuration.
var appConfig = require("../../../../app/js/app/config"),
  cfgId = !!window.__karma__ ? "karma" : "browser";

appConfig.storeName = "notes-browserify-" + cfgId + "-mocha";

// Require each module directly.
appConfig.useLocalStorage ?
  require("./collections/notes.spec") :
  require("./collections/notes-rest.spec");

// require("./models/note.spec");
// require("./routers/router.spec");
// require("./views/note.spec");
// require("./views/note-nav.spec");
// require("./views/note-view.spec");
// require("./views/notes.spec");
// require("./views/notes-filter.spec");
// require("./views/notes-item.spec");

/**
 * Test dependencies.
 *
 * This file lists out all of the individual spec (test) files so that they
 * are run by our infrastructure.
 */
// App configuration.
var appConfig = require("../../../../app/js/app/config"),
  cfgId = !!window.__karma__ ? "karma" : "browser";

appConfig.storeName = "notes-browserify-" + cfgId + "-mocha";

// Require each module directly.
appConfig.useLocalStorage ?
  require("./collections/notes.spec") :
  require("./collections/notes-rest.spec");

require("./models/note.spec");
// TODO require("./routers/router.spec");
// require("./views/note.spec");
// require("./views/note-nav.spec");
// require("./views/note-view.spec");
// require("./views/notes.spec");
// require("./views/notes-filter.spec");
// require("./views/notes-item.spec");

Add models (router currently failing)

Add models (router currently failing)


const JSUnit = imports.jsUnit;
// application/javascript;version=1.8
function testBasic1() {
    var foo = 1+1;
    JSUnit.assertEquals(2, foo);
}

JSUnit.gjstestRun(this, JSUnit.setUp, JSUnit.tearDown);

const JSUnit = imports.jsUnit;
// application/javascript;version=1.8
function testBasic1() {
    var foo = 1+1;
    JSUnit.assertEquals(2, foo);
}

function testFakeFailure() {
    var foo = 1+1;
    JSUnit.assertEquals(5, foo);
}

JSUnit.gjstestRun(this, JSUnit.setUp, JSUnit.tearDown);

Add a fake test failure

Add a fake test failure

Do not adjust your television. This is to test automated test
infrastructure and will (hopefully) be reverted immediately
afterwards.


'use strict';

/**
* Node version.
*
* @module @stdlib/process/node-version
* @type {(string|null)}
*
* @example
* var semver = require( 'semver' );
* var VERSION = require( '@stdlib/process/node-version' );
*
* if ( semver.lt( VERSION, '1.0.0' ) ) {
*    console.log( 'Running on a pre-io.js version...' );
* }
* else if ( semver.lt( VERSION, '4.0.0' ) ) {
*    console.log( 'Running on an io.js version...' );
* }
* else {
*    console.log( 'Running on a post-io.js version...' );
* }
*/

// MODULES //

var IS_NODE = require( '@stdlib/assert/is-node' );

// MAIN //

var VERSION;
if ( IS_NODE ) {
	VERSION = require( './version.js' );
} else {
	VERSION = require( './browser.js' );
}

// EXPORTS //

module.exports = VERSION;

'use strict';

/**
* Node version.
*
* @module @stdlib/process/node-version
* @type {(string|null)}
*
* @example
* var semver = require( 'semver' );
* var VERSION = require( '@stdlib/process/node-version' );
*
* if ( semver.lt( VERSION, '1.0.0' ) ) {
*    console.log( 'Running on a pre-io.js version...' );
* }
* else if ( semver.lt( VERSION, '4.0.0' ) ) {
*    console.log( 'Running on an io.js version...' );
* }
* else {
*    console.log( 'Running on a post-io.js version...' );
* }
*/

// MODULES //

var IS_NODE = require( '@stdlib/assert/is-node' );
var node = require( './version.js' );
var browser = require( './browser.js' );

// MAIN //

var VERSION;
if ( IS_NODE ) {
	VERSION = node;
} else {
	VERSION = browser;
}

// EXPORTS //

module.exports = VERSION;

Refactor to avoid dynamic module resolution


/* eslint-env mocha */
const BubbleSort = require('../../../src').Algorithms.Sorting.BubbleSort;
const assert = require('assert');

describe('BubbleSort', () => {
  it('should have no data when empty initialization', () => {
    const inst = new BubbleSort();
    assert.equal(inst.size, 0);
  });

  it('should sort the array', () => {
    const inst = new BubbleSort([2, 1, 3, 4]);
    assert.equal(inst.size, 4);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4]);
    assert.deepEqual(inst.sortedList, [1, 2, 3, 4]);
    assert.equal(inst.toString(), '1, 2, 3, 4');
  });
});

/* eslint-env mocha */
const BubbleSort = require('../../../src').Algorithms.Sorting.BubbleSort;
const assert = require('assert');

describe('BubbleSort', () => {
  it('should have no data when empty initialization', () => {
    const inst = new BubbleSort();
    assert.equal(inst.size, 0);
    assert.deepEqual(inst.unsortedList, []);
    assert.deepEqual(inst.sortedList, []);
  });

  it('should sort the array', () => {
    const inst = new BubbleSort([2, 1, 3, 4]);
    assert.equal(inst.size, 4);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4]);
    assert.deepEqual(inst.sortedList, [1, 2, 3, 4]);
    assert.equal(inst.toString(), '1, 2, 3, 4');
  });
});

Test Bubble Sort: Test for empty arrays

Test Bubble Sort: Test for empty arrays