(function() {
  angular.module('notely.login')
    .factory('AuthInterceptor', AuthInterceptor);

  function AuthInterceptor() {
    return {
      request: function(config) {
        return config;
      }
    }
  }

  angular.module('notely')
    .config(function($httpProvider) {
      return $httpProvider.interceptors.push('AuthInterceptor');
    });
})();

(function() {
  angular.module('notely.login')
    .factory('AuthInterceptor', AuthInterceptor);

  AuthInterceptor['$inject'] = ['AuthToken'];
  function AuthInterceptor(AuthToken) {
    return {
      request: function(config) {
        var token = AuthToken.get();
        if (token) {
          config.headers['Authorization'] = token;
        }
        return config;
      }
    }
  }

  angular.module('notely')
    .config(function($httpProvider) {
      return $httpProvider.interceptors.push('AuthInterceptor');
    });
})();

Add auth header if token is present.


/**
 *	fills the righthandside flexTab-Bar with the relevant tools
 *	@see packages/rocketchat-livechat/client/ui.js
 *	@see packages/rocketchat-lib/client/defaultTabBars.js
 */

RocketChat.TabBar.addGroup('starred-messages', ['request', 'expertise']);
RocketChat.TabBar.addGroup('push-notifications', ['request', 'expertise']);

RocketChat.TabBar.addButton({
	groups: ['request', 'expertise', 'live'],
	id: 'external-search',
	i18nTitle: 'Knowledge_Base',
	icon: 'icon-lightbulb',
	template: 'dbsAI_externalSearch',
	order: 0
});

RocketChat.TabBar.addButton({
	groups: ['request', 'expertise'],
	id: 'channel-settings',
	i18nTitle: 'Room_Info',
	icon: 'icon-info-circled',
	template: 'channelSettings',
	order: 1
});

RocketChat.TabBar.addButton({
	groups: ['request', 'expertise'],
	id: 'members-list',
	i18nTitle: 'Members_List',
	icon: 'icon-users',
	template: 'membersList',
	order: 3
});

RocketChat.TabBar.addButton({
	groups: ['request', 'expertise'],
	id: 'message-search',
	i18nTitle: 'Search',
	icon: 'icon-search',
	template: 'messageSearch',
	order: 10
});

RocketChat.TabBar.addButton({
	groups: ['request', 'expertise'],
	id: 'uploaded-files-list',
	i18nTitle: 'Room_uploaded_file_list',
	icon: 'icon-attach',
	template: 'uploadedFilesList',
	order: 30
});

/**
 *	fills the righthandside flexTab-Bar with the relevant tools
 *	@see packages/rocketchat-livechat/client/ui.js
 *	@see packages/rocketchat-lib/client/defaultTabBars.js
 */

RocketChat.TabBar.addGroup('starred-messages', ['request', 'expertise']);
RocketChat.TabBar.addGroup('push-notifications', ['request', 'expertise']);
RocketChat.TabBar.addGroup('channel-settings', ['request', 'expertise']);
RocketChat.TabBar.addGroup('members-list', ['request', 'expertise']);
RocketChat.TabBar.addGroup('message-search',['request', 'expertise']);
RocketChat.TabBar.addGroup('uploaded-files-list',['request', 'expertise']);

RocketChat.TabBar.addButton({
	groups: ['request', 'expertise', 'live'],
	id: 'external-search',
	i18nTitle: 'Knowledge_Base',
	icon: 'icon-lightbulb',
	template: 'dbsAI_externalSearch',
	order: 0
});

Fix tabbar for requests and expertise


'use strict';

var _         = require('lodash');
var commander = require('commander');
var path      = require('path');
var Queue     = require('gear').Queue;
var registry  = require('./tasks');

var build, hasTarget, target,
    targets = ['browser', 'cdn', 'node'];

commander
  .usage('[options] [<languages ...>]')
  .option('-n, --no-compress', 'Disable compression')
  .option('-t, --target <name>', 'Build for target <name> ' +
                                 '[browser, cdn, node]',
                                 'browser')
  .parse(process.argv);

hasTarget = _.contains(targets, commander.target);

target = './' + (hasTarget ? commander.target : 'browser');
build  = require(target);

global.dir       = {};
global.dir.root  = path.dirname(__dirname);
global.dir.build = path.join(dir.root, 'build');

new Queue({ registry: registry })
  .clean(dir.build)
  .log('Starting build.')
  .tasks(build(commander))
  .log('Finished build.')
  .run();

'use strict';

var _         = require('lodash');
var commander = require('commander');
var path      = require('path');
var Queue     = require('gear').Queue;
var registry  = require('./tasks');

var build, hasTarget, target,
    targets = ['browser', 'cdn', 'node'];

commander
  .usage('[options] [<languages ...>]')
  .option('-n, --no-compress', 'Disable compression')
  .option('-t, --target <name>', 'Build for target [browser, cdn, node]',
                                 /^(browser|cdn|node$)/i, 'browser')
  .parse(process.argv);

hasTarget = _.contains(targets, commander.target);

target = './' + (hasTarget ? commander.target : 'browser');
build  = require(target);

global.dir       = {};
global.dir.root  = path.dirname(__dirname);
global.dir.build = path.join(dir.root, 'build');

new Queue({ registry: registry })
  .clean(dir.build)
  .log('Starting build.')
  .tasks(build(commander))
  .log('Finished build.')
  .run();

Use regular expression for target types


import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { AuthAPI } from '../auth'

const httpLink = createHttpLink({
  uri: process.env.GRAPHQL_URL || 'http://localhost:3001/graphql'
})

const authLink = setContext((_, { headers }) => {
  const token = AuthAPI.getToken()

  if (token) {
    return {
      headers: {
        ...headers,
        authorization: `Bearer ${token}`
      }
    }
  }
  return { headers }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

export default client

import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { AuthAPI } from '../auth'

const httpLink = createHttpLink({
  uri: process.env.REACT_APP_GRAPHQL_URL || 'http://localhost:3001/graphql'
})

const authLink = setContext((_, { headers }) => {
  const token = AuthAPI.getToken()

  if (token) {
    return {
      headers: {
        ...headers,
        authorization: `Bearer ${token}`
      }
    }
  }
  return { headers }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

export default client

Change GRAPHQ_URL env variable to default react app config


(function() {
  'use strict';

  angular
    .module('app.auth')
    .controller('AuthController', AuthController);

  AuthController.$inject = ['$location', '$firebaseAuth'];

  function AuthController($location, $firebaseAuth) {
    var vm = this;
    var firebaseReference = new Firebase('https://waitandeat-v2-demo.firebaseio.com/');
    var firebaseAuthObject = $firebaseAuth(firebaseReference);

    vm.user = {
      email: '',
      password: ''
    };

    vm.register = register;
    vm.login = login;
    vm.logout = logout;

    function register(user) {
      return firebaseAuthObject.$createUser(user)
        .then(function() {
          return vm.login(user);
        })
        .catch(function(error) {
          console.log(error);
        });
    }

    function login(user) {
      return firebaseAuthObject.$authWithPassword(user)
        .then(function(loggedInUser) {
          console.log(loggedInUser);
          $location.path('/waitlist');
        })
        .catch(function(error) {
          console.log(error);
        });
    }

    function logout() {
      firebaseAuthObject.$unauth();
      $location.path('/');
    }
  }

})();

(function() {
  'use strict';

  angular
    .module('app.auth')
    .controller('AuthController', AuthController);

  AuthController.$inject = ['$location', '$firebaseAuth', 'FIREBASE_URL'];

  function AuthController($location, $firebaseAuth, FIREBASE_URL) {
    var vm = this;
    var firebaseReference = new Firebase(FIREBASE_URL);
    var firebaseAuthObject = $firebaseAuth(firebaseReference);

    vm.user = {
      email: '',
      password: ''
    };

    vm.register = register;
    vm.login = login;
    vm.logout = logout;

    function register(user) {
      return firebaseAuthObject.$createUser(user)
        .then(function() {
          return vm.login(user);
        })
        .catch(function(error) {
          console.log(error);
        });
    }

    function login(user) {
      return firebaseAuthObject.$authWithPassword(user)
        .then(function(loggedInUser) {
          console.log(loggedInUser);
          $location.path('/waitlist');
        })
        .catch(function(error) {
          console.log(error);
        });
    }

    function logout() {
      firebaseAuthObject.$unauth();
      $location.path('/');
    }
  }

})();

Use FIREBASE_URL in auth module.


// Avoid `console` errors in browsers that lack a console.
(function() {
    var method;
    var noop = function () {};
    var methods = [
        'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
        'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
        'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
        'timeStamp', 'trace', 'warn'
    ];
    var length = methods.length;
    var console = (window.console = window.console || {});

    while (length--) {
        method = methods[length];

        // Only stub undefined methods.
        if (!console[method]) {
            console[method] = noop;
        }
    }
}());

// Place any jQuery/helper plugins in here.

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-9335012-1']);
_gaq.push(['_trackPageview']);

(function() {
    var ga = document.createElement('script');
    ga.type = 'text/javascript';
    ga.async = true;
    ga.src = ('https:' === document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(ga, s);
})();

// Add custom class to our download links

$('#binaries, #pdb-files').find('.external').each(function() {
    $(this).addClass("sourceforge_accelerator_link");
});

Use the SF download links (hack since we can't specify a class with sphinx)


/* global process */
var WebDriver = require("selenium-webdriver");

var driver;
if (process.env.SAUCE_USERNAME !== undefined) {
    var browserArray = process.env.BROWSER.split(':');
    driver = new WebDriver.Builder().usingServer(
        'http://'+ process.env.SAUCE_USERNAME+':'+process.env.SAUCE_ACCESS_KEY+'@ondemand.saucelabs.com:80/wd/hub'
    ).withCapabilities({
        "tunnel-identifier": process.env.TRAVIS_JOB_NUMBER,
        "build": process.env.TRAVIS_JOB_NUMBER,
        "username": process.env.SAUCE_USERNAME,
        "accessKey": process.env.SAUCE_ACCESS_KEY,
    }).forBrowser(browserArray[0], browserArray[1], browserArray[2]).build();
} else {
    driver = new WebDriver.Builder().withCapabilities({ browserName: "chrome" }).build();
}

driver.get('http://localhost:3000/assert/');
var report = driver.wait(WebDriver.until.elementLocated(WebDriver.By.className("report")), 5000);
report.getAttribute("class").then(function (cls) {
    driver.quit();
    if (!cls) {
        throw new Error("cls is null");
    } else if (cls.indexOf("failure") !== -1) {
        throw new Error("cls contains the word failure");
    } else if (cls.indexOf("success") === -1) {
        throw new Error("cls does not contain the word success");
    }
});

/* global process */
var WebDriver = require("selenium-webdriver");

var driver;
if (process.env.SAUCE_USERNAME !== undefined) {
    var browserArray = process.env.BROWSER.split(':');
    driver = new WebDriver.Builder().usingServer(
        'http://'+ process.env.SAUCE_USERNAME+':'+process.env.SAUCE_ACCESS_KEY+'@ondemand.saucelabs.com:80/wd/hub'
    ).withCapabilities({
        "tunnel-identifier": process.env.TRAVIS_JOB_NUMBER,
        "build": process.env.TRAVIS_JOB_NUMBER,
        "username": process.env.SAUCE_USERNAME,
        "accessKey": process.env.SAUCE_ACCESS_KEY,
    }).forBrowser(browserArray[0], browserArray[1], browserArray[2]).build();
} else {
    driver = new WebDriver.Builder().withCapabilities({ browserName: "chrome" }).build();
}

driver.get('http://localhost:3000/assert/');
var report = driver.wait(WebDriver.until.elementLocated(WebDriver.By.className("report")), 5000);
report.getAttribute("class").then(function (cls) {
    report.getText().then(function (text) {
        console.log("\n-----\n" + text + "\n-----");
        driver.quit();
        if (!cls) {
            throw new Error("cls is null");
        } else if (cls.indexOf("failure") !== -1) {
            throw new Error("cls contains the word failure");
        } else if (cls.indexOf("success") === -1) {
            throw new Error("cls does not contain the word success");
        }
    });
});

Make the selenium test log the content of the /assert report to the console


import navigateTo from 'uni-helpers/navigate-to'
import redirectTo from '../../helpers/redirect-to'
import previewImage from '../../helpers/normalize-preview-image'

function addSafeAreaInsets (result) {
  if (result.safeArea) {
    const safeArea = result.safeArea
    result.safeAreaInsets = {
      top: safeArea.top,
      left: safeArea.left,
      right: result.windowWidth - safeArea.right,
      bottom: result.windowHeight - safeArea.bottom
    }
  }
}
export const protocols = {
  redirectTo,
  navigateTo,
  previewImage,
  getSystemInfo: {
    returnValue: addSafeAreaInsets
  },
  getSystemInfoSync: {
    returnValue: addSafeAreaInsets
  }
}
export const todos = [
  'vibrate',
  'preloadPage',
  'unPreloadPage',
  'loadSubPackage'
]
export const canIUses = []

// import navigateTo from 'uni-helpers/navigate-to'
import redirectTo from '../../helpers/redirect-to'
import previewImage from '../../helpers/normalize-preview-image'

function addSafeAreaInsets (result) {
  if (result.safeArea) {
    const safeArea = result.safeArea
    result.safeAreaInsets = {
      top: safeArea.top,
      left: safeArea.left,
      right: result.windowWidth - safeArea.right,
      bottom: result.windowHeight - safeArea.bottom
    }
  }
}
export const protocols = {
  redirectTo,
  // navigateTo,  // 由于在微信开发者工具的页面参数，会显示__id__参数，因此暂时关闭mp-weixin对于navigateTo的AOP
  previewImage,
  getSystemInfo: {
    returnValue: addSafeAreaInsets
  },
  getSystemInfoSync: {
    returnValue: addSafeAreaInsets
  }
}
export const todos = [
  'vibrate',
  'preloadPage',
  'unPreloadPage',
  'loadSubPackage'
]
export const canIUses = []

Remove mp-weixin's AOP of 'navigateTo'


import { createHttpLink } from 'apollo-link-http';

export default createHttpLink({ uri: 'https://api.newspring.cc/graphql' });
// export default createHttpLink({ uri: 'http://localhost:8888/graphql' });

Make it easy to swap out dev code for now


/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * External dependencies
 */
import { sanitizeHTML } from 'assets/js/util';

export const settingsDetails = () => {
	const { dashboardPermalink } = global.googlesitekit;

	const content = sprintf(
		/* translators: %s is the URL to the Site Kit dashboard. */
		__( 'To view insights, visit the dashboard.', 'google-site-kit' ),
		dashboardPermalink
	);

	return (

	);
};

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { sanitizeHTML } from '../../../util';

export const settingsDetails = () => {
	const { dashboardPermalink } = global.googlesitekit;

	const content = sprintf(
		/* translators: %s is the URL to the Site Kit dashboard. */
		__( 'To view insights, visit the dashboard.', 'google-site-kit' ),
		dashboardPermalink
	);

	return (

	);
};

Use relative import for util for now.


$(document).ready(function() {
    // There is no default option for disabling a field with django-bootstrap4
    $('#id_mother_tongue').prop('disabled', true);

    // Set tooltips
    $('[data-toggle="tooltip"]').tooltip();
});

$('#id_degree_programme_options').change(function() {
    if (this.value === 'extra') {
        $('#unknown_degree').show();
        $('#unknown_degree input').val('');
    } else {
        $('#unknown_degree').hide();
        $('#unknown_degree input').val(this.value);
    }
});

$('input:radio[name="language"]').change(function() {
    if ($(this).is(':checked')) {
        if ($(this).val() == 'extra') {
            $('#id_mother_tongue').prop('disabled', false);
            $('#id_mother_tongue').val('');
        } else {
            $('#id_mother_tongue').prop('disabled', true);
            $('#id_mother_tongue').val(this.value);
        }
    }
});

$(document).ready(function() {
    // There is no default option for setting readonly a field with django-bootstrap4
    $('#id_mother_tongue').prop('readonly', true);

    // Set tooltips
    $('[data-toggle="tooltip"]').tooltip();
});

$('#id_degree_programme_options').change(function() {
    if (this.value === 'extra') {
        $('#unknown_degree').show();
        $('#unknown_degree input').val('');
    } else {
        $('#unknown_degree').hide();
        $('#unknown_degree input').val(this.value);
    }
});

$('input:radio[name="language"]').change(function() {
    if ($(this).is(':checked')) {
        if ($(this).val() == 'extra') {
            $('#id_mother_tongue').prop('readonly', false);
            $('#id_mother_tongue').val('');
        } else {
            $('#id_mother_tongue').prop('readonly', true);
            $('#id_mother_tongue').val(this.value);
        }
    }
});

Put readonly on mother tongue instead of disabled


// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
	preset: 'ts-jest',
	testEnvironment: 'node',
	collectCoverage: true,
	collectCoverageFrom: [
		'./src/**/*.ts',
	],
	coverageDirectory: 'build',
	globals: {
		'ts-jest': {
			tsconfig: 'test/tsconfig.json',
		},
	},
};

// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
	preset: 'ts-jest',
	testEnvironment: 'node',
	collectCoverage: true,
	collectCoverageFrom: [
		'./src/**/*.ts',
		'!./src/*.ts',
	],
	coverageDirectory: 'build',
	globals: {
		'ts-jest': {
			tsconfig: 'test/tsconfig.json',
		},
	},
};

Exclude entries from unit test report


const got = require('got');

module.exports = data => {
  if (typeof data === 'string') {
    data = { url: data };
  }
  data.method = data.method || 'get';
  data.options = Object.assign({ json: true }, data.options);
  return {
    check: () => got[data.method](data.url, data.options),
    data: { url: data.url },
  };
};

const got = require('got');

module.exports = data => {
  if (typeof data === 'string') {
    data = { url: data };
  }
  data.method = data.method || 'get';
  return {
    check: () => got[data.method](data.url, data.options),
    data: { url: data.url },
  };
};

Remove the JSON parse for the health response


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

goog.module('arithmetic_module_test');
goog.setTestOnly('arithmetic_module_test');

var add = goog.require('arithmetic_module.add');
var testSuite = goog.require('goog.testing.testSuite');

testSuite({
  testAdd: function() {
    assertEquals(4, add(2, 2));
  }
});

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

goog.module('arithmetic_module_test');
goog.setTestOnly('arithmetic_module_test');

var add = goog.require('arithmetic_module.add');
var testSuite = goog.require('goog.testing.testSuite');

goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');

testSuite({
  testAdd: function() {
    assertEquals(4, add(2, 2));
  }
});

Add missing jsunit and asserts requires to the goog.module test


/*jshint node:true*/
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    // Add options here
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};

/*jshint node:true*/
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    sourcemaps: {
      enabled: false
    },
    sassOptions: {
      outputStyle: 'compressed',
      sourceMap: false
    },
    fingerprint: {
      enabled: false
    }
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};

Disable sourcemaps and compress CSS


Package.describe({
  name: "shell-server",
  version: "0.2.2",
  summary: "Server-side component of the `meteor shell` command.",
  documentation: "README.md"
});

Package.onUse(function(api) {
  api.use("ecmascript@0.5.7", "server");
  api.mainModule("main.js", "server");
});

Package.describe({
  name: "shell-server",
  version: "0.2.3",
  summary: "Server-side component of the `meteor shell` command.",
  documentation: "README.md"
});

Package.onUse(function(api) {
  api.use("ecmascript@0.5.7", "server");
  api.mainModule("main.js", "server");
});

Bump version in preparation for publishing.


core.controller('LoginController', function ($controller, $location, $scope, RestApi, StorageService, User) {

    angular.extend(this, $controller('AbstractController', {$scope: $scope}));

    $scope.account = {
    	email: '',
    	password: ''
    };

	$scope.login = function() {
		RestApi.anonymousGet({
			controller: 'auth',
			method: 'login',
			data: $scope.account
		}).then(function(data) {

			if(typeof data.payload.JWT == 'undefined') {
				console.log("User does not exist!");
			}
			else {
				StorageService.set("token", data.payload.JWT.tokenAsString);

				delete sessionStorage.role;

				var user = User.login();

				User.ready().then(function() {
					StorageService.set("role", user.role);
				});
			}
		});
	};

});

core.controller('LoginController', function ($controller, $location, $scope, RestApi, StorageService, User) {

    angular.extend(this, $controller('AbstractController', {$scope: $scope}));

    $scope.account = {
    	email: '',
    	password: ''
    };

	$scope.login = function() {
		RestApi.anonymousGet({
			controller: 'auth',
			method: 'login',
			data: $scope.account
		}).then(function(data) {

			if(typeof data.payload.JWT == 'undefined') {
				console.log("User does not exist!");
			}
			else {

				$scope.account = {
			    	email: '',
			    	password: ''
			    };

				StorageService.set("token", data.payload.JWT.tokenAsString);

				delete sessionStorage.role;

				var user = User.login();

				User.ready().then(function() {
					StorageService.set("role", user.role);
				});
			}
		});
	};

});

Clear login form upon login.


/*
 * Copyright (C) 2021 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

const fs = require('fs')
const path = require('path')

/**
 * This returns the contents of the translations for the given package and locale
 */
async function getTranslationList(packageName, locale) {
  const jsonData = await fs.promises.readFile(
    path.resolve(__dirname, `../lib/${packageName}/${locale}.json`),
    {encoding: 'utf8'}
  )
  return jsonData
}

module.exports = getTranslationList

/*
 * Copyright (C) 2021 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

const fs = require('fs')
const path = require('path')

/**
 * This returns the contents of the translations for the given package and locale
 */
async function readTRanslationFile(packageName, locale) {
  const filePath = path.resolve(__dirname, `../lib/${packageName}/${locale}.json`)
  const jsonData = await fs.promises.readFile(filePath, {encoding: 'utf8'})
  // sanity check
  try {
    JSON.parse(jsonData)
  } catch (ex) {
    console.log(ex)
    throw new Error(`Failed parsing content from ${filePath}`)
  }
  return jsonData
}

module.exports = readTRanslationFile

Add a sanity check when reading translation json data


/* global __WEB__*/

const scrollTopMiddleware = () => (next) => (action) => {
    if (action.type === '@@router/UPDATE_PATH') {
        window.scrollTo(0, 0);
    }

    return next(action);
};

export default () => {
    if (__WEB__) {
        return [scrollTopMiddleware];
    }

    return [];
};

/* global __WEB__*/

const scrollTopMiddleware = () => (next) => (action) => {
    if (action.type === '@@router/LOCATION_CHANGE') {
        window.scrollTo(0, 0);
    }

    return next(action);
};

export default () => {
    if (__WEB__) {
        return [scrollTopMiddleware];
    }

    return [];
};

Update middleware to support new router action naming


'use strict';

angular.module('Game', [])
.service('GameManager', function() {
        // Create a new game
        this.newGame = function() {};
        // Handle user action
        this.move = function() {};
        // Update the score
        this.updateScore = function() {};
        // Check is there any move left
        this.moveAvailable = function() {};
    });

'use strict';

angular.module('Game', [])
.service('GameManager', ['GridService', function(GridService) {
        // Create a new game
        this.newGame = function() {};
        // Handle user action
        this.move = function() {};
        // Update the score
        this.updateScore = function() {};
        // Check is there any move left
        this.moveAvailable = function() {
                return GridService.anyCellsAvailable() || GridService.tileMatchesAvailable();
        };
    }]);

Create GameManager.moveAvailable method, and pass unit test.


/*
 * Copyright (C) 2014 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

import router from './react/router'

router.start()

/*
 * Copyright (C) 2014 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

import router from './react/router'
import ready from '@instructure/ready'

ready(() => {
  router.start()
})

Fix lti collaborations page unresponsive on load in chrome


var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    prefix = require('gulp-autoprefixer'),
    livereload = require('gulp-livereload'),
    util = require('gulp-util');

var LIVERELOAD_PORT = 35729,
    EXPRESS_PORT = 8181,
    EXPRESS_ROOT = __dirname;

function startExpress() {
    var express = require('express');
    var app = express();
    app.use(express.static(EXPRESS_ROOT));
    app.listen(EXPRESS_PORT);
}

gulp.task('default', function(){

    util.log('Starting express server.');
    startExpress();

    // Watch HTML files
    gulp.watch('design/*.html', function(event){
        util.log( 'HTML files changed.');
        gulp.src('design/*.html')
            .pipe(livereload());
    });

    // Watch sass files
    gulp.watch('src/sass/**/*.sass', function(event){
        util.log( 'Sass files changed recompiling sass files.');

        gulp.src('src/sass/*.sass')
                .pipe(sass({ style: 'compressed' }))
                .pipe(gulp.dest('static/css'))
                .pipe(livereload());
        util.log('Sass compilation done.');

        // util.log('Triggering livereload');
        // fireLivereloadChange(event);
    });
});

var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    prefix = require('gulp-autoprefixer'),
    livereload = require('gulp-livereload'),
    util = require('gulp-util');

var LIVERELOAD_PORT = 35729,
    EXPRESS_PORT = 8181,
    EXPRESS_ROOT = __dirname;

function startExpress() {
    var express = require('express');
    var app = express();
    app.use(express.static(EXPRESS_ROOT));
    app.listen(EXPRESS_PORT);
}

gulp.task('default', function(){

    util.log('Starting express server on port '.EXPRESS_ROOT);
    startExpress();

    // Watch HTML files
    gulp.watch('design/*.html', function(event){
        util.log( 'HTML files changed.');
        gulp.src('design/*.html')
            .pipe(livereload());
    });

    // Watch sass files
    gulp.watch('src/sass/**/*.sass', function(event){
        util.log( 'Sass files changed recompiling sass files.');

        gulp.src('src/sass/*.sass')
                .pipe(sass({ style: 'compressed' }))
                .pipe(gulp.dest('static/css'))
                .pipe(livereload());
        util.log('Sass compilation done.');

        // util.log('Triggering livereload');
        // fireLivereloadChange(event);
    });
});

Update server port to log


// Reverse Array In Place

/*RULES:
  Take array as parameter
    Reverse array
    Return reversed array

  NOTES:
  Can't create new empty array to push in
  Must modify given array
  Can't use array.reverse();
*/

/*PSEUDOCODE

  1) Find array length
  2) Until last element is first element,
    2a) Push first element to end of array
    2b) Splice first element out of there
  3) When done, return array
*/

// Reverse Array In Place

/*RULES:
  Take array as parameter
    Reverse array
    Return reversed array

  NOTES:
  Can't create new empty array to push in
  Must modify given array
  Can't use array.reverse();
*/

/*PSEUDOCODE

  1) Find array length
  2) Create variable "stopper" for last element in array
  2) (array.length - 1) times do:
    2a) Push element previous to "stopper" to the end of the array
    2b) Splice that same element out from in front of 'stopper'
  3) When done, return reversed array
*/

function reverseArray(arr){
  var count = arr.length;

}

Update pseudocde with newer plan, begin reverseArr function


'use strict'
var tape = require('tape')
var pull = require('pull-stream')

var createSSB = require('./create-ssb')
var keys = require('ssb-keys').generate()
var content = { type: 'whatever' }

tape('load', function (t) {
  t.plan(1)
  var ssb = createSSB('test-ssb-feed', { keys, temp: false })

  ssb.createFeed().add(content, function (err, msg) {
    if (err) throw err
    // console.log(msg)

    ssb.close(function () {
      t.ok(true, 'closes + runs callback')
    })
  })
})

tape('reopen', function (t) {
  t.plan(1)
  var ssb = createSSB('test-ssb-feed', { keys, temp: false })

  pull(
    ssb.createLogStream(),
    pull.collect(function (err, ary) {
      if (err) throw err

      t.deepEqual(ary[0].value.content, content, 'reopen works fine')
    })
  )
})

'use strict'
var tape = require('tape')
var pull = require('pull-stream')

var createSSB = require('./create-ssb')
var keys = require('ssb-keys').generate()
var content = { type: 'whatever' }

const name = `test-ssb-close-${Date.now()}`

tape('load', function (t) {
  t.plan(1)
  var ssb = createSSB(name, { keys, temp: false })

  ssb.createFeed().add(content, function (err, msg) {
    if (err) throw err
    // console.log(msg)

    ssb.close(function () {
      t.ok(true, 'closes + runs callback')
    })
  })
})

tape('reopen', function (t) {
  t.plan(1)
  var ssb = createSSB(name, { keys, temp: false })

  pull(
    ssb.createLogStream(),
    pull.collect(function (err, ary) {
      if (err) throw err

      t.deepEqual(ary[0].value.content, content, 'reopen works fine')
    })
  )
})

Use deterministic name to make test always fail


'use strict';
const gulp=require('gulp');
const $=require('gulp-load-plugins')();

gulp.task('eslint',function(){
  return gulp.src(['*.js','api/**/*.js'])
  .pipe($.gitmodified('modified'))
  .pipe($.eslint())
  .pipe($.eslint.format())
  .pipe($.eslint.failOnError());
});

gulp.task('yamlValidate',function(){
  return gulp.src(['./config/*.{yaml,yml}'])
  .pipe($.yamlValidate());
});

gulp.task('lint',gulp.parallel([
  'eslint',
  'yamlValidate'
]));

gulp.task('hooks',function(){
  return gulp.src(['.git-hooks/pre-commit','.git-hooks/post-merge'])
  .pipe($.sym(
    ['.git/hooks/pre-commit','.git/hooks/post-merge'],
    {relative: true,force: true}
  ));
});

'use strict';
const gulp=require('gulp');
const $=require('gulp-load-plugins')();

gulp.task('eslint',function(){
  return gulp.src(['*.js','api/**/*.js'])
  .pipe($.gitmodified('modified'))
  .pipe($.eslint())
  .pipe($.eslint.format())
  .pipe($.eslint.failOnError());
});

gulp.task('yamlValidate',function(){
  return gulp.src(['api/*.yml','config/*.{yaml,yml}'])
  .pipe($.yamlValidate());
});

gulp.task('lint',gulp.parallel([
  'eslint',
  'yamlValidate'
]));

gulp.task('hooks',function(){
  return gulp.src(['.git-hooks/pre-commit','.git-hooks/post-merge'])
  .pipe($.sym(
    ['.git/hooks/pre-commit','.git/hooks/post-merge'],
    {relative: true,force: true}
  ));
});

Validate swagger spec in gulp task


/*
 * Configuration values needed in js codes
 *
 * NOTE:
 * Please use the following command to avoid accidentally committing personal changes
 * git update-index --assume-unchanged src/javascript/config.js
 *
 */

function getAppId() {
  return localStorage.getItem('config.app_id') ? localStorage.getItem('config.app_id') :
               /staging\.binary\.com/i.test(window.location.hostname) ? '1098' : '1';
}

function getSocketURL() {
    var server_url = localStorage.getItem('config.server_url');
    if(!server_url) server_url = (/staging\.binary\.com/i.test(window.location.hostname) ? 'www2' : 'ws') + '.binaryws.com';
    return 'wss://' + server_url + '/websockets/v3';
}

/*
 * Configuration values needed in js codes
 *
 * NOTE:
 * Please use the following command to avoid accidentally committing personal changes
 * git update-index --assume-unchanged src/javascript/config.js
 *
 */

function getAppId() {
  return localStorage.getItem('config.app_id') ? localStorage.getItem('config.app_id') :
               /staging\.binary\.com/i.test(window.location.hostname) ? '1098' : '1';
}

function getSocketURL() {
    var server_url = localStorage.getItem('config.server_url'),
        loginid = $.cookie('loginid');
    if(!server_url) server_url =
        /staging\.binary\.com/i.test(window.location.hostname) ? 'www2' :
            (loginid && !/^VRT/.test(loginid) ? 'green' : 'blue') +
        '.binaryws.com';
    return 'wss://' + server_url + '/websockets/v3';
}

Modify server url to follow blue/green


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

  afterInstall: function() {
    return this.addBowerPackageToProject('dom-ruler#0.1.4');
  }
};

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

  afterInstall: function() {
    return this.addBowerPackageToProject('dom-ruler#0.1.5');
  }
};

Upgrade dom-ruler version in blueprint


import fs from 'fs'
import path from 'path'
import resolve from 'resolve'
import detective from 'detective'

function createModule(file) {
  const source = fs.readFileSync(file, 'utf-8')
  const requires = detective(source)

  return { file, requires }
}

export default function getModuleDependencies(entryFile) {
  const rootModule = createModule(entryFile)
  const modules = [rootModule]

  // Iterate over the modules, even when new
  // ones are being added
  for (const mdl of modules) {
    mdl.requires.forEach(dep => {
      const basedir = path.dirname(mdl.file)
      const depPath = resolve.sync(dep, { basedir })
      const depModule = createModule(depPath)

      modules.push(depModule)
    })
  }

  return modules
}

import fs from 'fs'
import path from 'path'
import resolve from 'resolve'
import detective from 'detective'

function createModule(file) {
  const source = fs.readFileSync(file, 'utf-8')
  const requires = detective(source)

  return { file, requires }
}

export default function getModuleDependencies(entryFile) {
  const rootModule = createModule(entryFile)
  const modules = [rootModule]

  // Iterate over the modules, even when new
  // ones are being added
  for (const mdl of modules) {
    mdl.requires.forEach(dep => {
      try {
        const basedir = path.dirname(mdl.file)
        const depPath = resolve.sync(dep, { basedir })
        const depModule = createModule(depPath)

        modules.push(depModule)
      } catch (_err) {}
    })
  }

  return modules
}

Fix unresolved modules in config watcher


/*jshint node:true*/
module.exports = {
  description: '',
  normalizeEntityName: function() { }

  // locals: function(options) {
  //   // Return custom template variables here.
  //   return {
  //     foo: options.entity.options.foo
  //   };
  // }

  // afterInstall: function(options) {
  //   // Perform extra work here.
  // }
};

/*jshint node:true*/
let fs = require('fs');
let path = require('path');
let chalk = require('chalk');

module.exports = {
  description: '',
  normalizeEntityName: function() { },
  afterInstall() {
    let fullPath = path.join(this.project.root, 'app/templates/application.hbs');

    if (fs.existsSync(fullPath)) {
      let contents = fs.readFileSync(fullPath, { encoding: 'utf-8' });
      let toWrite = `{{head-layout}}\n${contents}`;

      fs.writeFileSync(fullPath, toWrite, { encoding: 'utf-8' });
    } else {
      let str = `You must add {{head-layout}} component to your topmost UI.
This is usually your app/templates/application.hbs, but was not found on your system.
Please see the README for more instructions https://github.com/ronco/ember-cli-head.`

      this.ui.writeLine(chalk.yellow(str));
    }
  }

  // locals: function(options) {
  //   // Return custom template variables here.
  //   return {
  //     foo: options.entity.options.foo
  //   };
  // }

  // afterInstall: function(options) {
  //   // Perform extra work here.
  // }
};

Add afterInstall to automatically add {{head-layout}} to application.hbs


/* eslint-env serviceworker */

// This makes a module available named "reconstructive"
importScripts('/reconstructive.js')

// Customize configs (defaults should work for IPWB out of the box)
// reconstructive.init({
//   version: 'reconstructive.js:v1',
//   urimPattern: self.location.origin + '/memento/<datetime>/<urir>',
//   showBanner: false
// })

// Add any custom exclusions or modify or delete default ones
//> reconstructive.exclusions
//< {
//<   notGet: f (event, config),
//<   localResource: f (event, config)
//< }
reconstructive.exclusions.selfScript = function (event, config) {
  event.request.url.endsWith('reconstructive.js')
}

// Pass a custom function to generate banner markup
// reconstructive.bannerCreator(f (event, rewritten, config))
// Or update the rewriting logic
// reconstructive.updateRewriter(f (event, rewritten, config))

// This is unnecessary, but can be useful for debugging or in future
self.addEventListener('install', function (event) {
  console.log('Installing ServiceWorker.')
})

// This is unnecessary, but can be useful for debugging or in future
self.addEventListener('activate', function (event) {
  console.log('Activating ServiceWorker.')
})

self.addEventListener("fetch", function(event) {
  console.log('A fetch event triggered:', event);
  // Add any custom logic here to conditionally call the reroute function
  reconstructive.reroute(event);
})

/* eslint-env serviceworker */

// This makes a module available named "reconstructive"
importScripts('/reconstructive.js')

// Customize configs (defaults should work for IPWB out of the box)
// reconstructive.init({
//   version: 'reconstructive.js:v1',
//   urimPattern: self.location.origin + '/memento/<datetime>/<urir>',
//   showBanner: false
// })

// Add any custom exclusions or modify or delete default ones
//> reconstructive.exclusions
//< {
//<   notGet: f (event, config),
//<   localResource: f (event, config)
//< }

// Pass a custom function to generate banner markup
// reconstructive.bannerCreator(f (event, rewritten, config))
// Or update the rewriting logic
// reconstructive.updateRewriter(f (event, rewritten, config))

// This is unnecessary, but can be useful for debugging or in future
self.addEventListener('install', function (event) {
  console.log('Installing ServiceWorker.')
})

// This is unnecessary, but can be useful for debugging or in future
self.addEventListener('activate', function (event) {
  console.log('Activating ServiceWorker.')
})

self.addEventListener("fetch", function(event) {
  console.log('A fetch event triggered:', event);
  // Add any custom logic here to conditionally call the reroute function
  reconstructive.reroute(event);
})

Revert "Adding exclusion for reconstructive.js loading"


import {Schema} from 'normalizr';
import {normalizeActionName} from '../common/helpers';

export const UnitServices = {
  MECHANICALLY_FROZEN_ICE: 33417,
  ICE_SKATING_FIELD: 33418,
  ICE_RINK: 33419,
  SPEED_SKATING_TRACK: 33420,
  SKI_TRACK: 33483,
  DOG_SKI_TRACK: 33492
};

export const IceSkatingServices = [
  UnitServices.MECHANICALLY_FROZEN_ICE,
  UnitServices.ICE_SKATING_FIELD,
  UnitServices.ICE_RINK,
  UnitServices.SPEED_SKATING_TRACK
];

export const SkiingServices = [
  UnitServices.SKI_TRACK,
  UnitServices.DOG_SKI_TRACK
];

export const SwimmingServices = [];

export const ServiceActions = {
  FETCH: normalizeActionName('service/FETCH'),
  RECEIVE: normalizeActionName('service/RECEIVE'),
  FETCH_ERROR: normalizeActionName('service/FETCH_ERROR')
};

export type UnitState = {
  isFetching: boolean,
  byId: Object,
  // Filtered arrays of ids
  all: Array<string>,
  skating: Array<string>,
  skiing: Array<string>,
  searchResults: Array<string>
};

export const serviceSchema = new Schema('service'/*, {}*/);

import {Schema} from 'normalizr';
import {normalizeActionName} from '../common/helpers';

export const UnitServices = {
  MECHANICALLY_FROZEN_ICE: 33417,
  ICE_SKATING_FIELD: 33418,
  ICE_RINK: 33419,
  SPEED_SKATING_TRACK: 33420,
  ICE_SKATING_ROUTE: 33421,
  SKI_TRACK: 33483,
  DOG_SKI_TRACK: 33492
};

export const IceSkatingServices = [
  UnitServices.MECHANICALLY_FROZEN_ICE,
  UnitServices.ICE_SKATING_FIELD,
  UnitServices.ICE_RINK,
  UnitServices.SPEED_SKATING_TRACK,
  UnitServices.ICE_SKATING_ROUTE
];

export const SkiingServices = [
  UnitServices.SKI_TRACK,
  UnitServices.DOG_SKI_TRACK
];

export const SwimmingServices = [];

export const ServiceActions = {
  FETCH: normalizeActionName('service/FETCH'),
  RECEIVE: normalizeActionName('service/RECEIVE'),
  FETCH_ERROR: normalizeActionName('service/FETCH_ERROR')
};

export type UnitState = {
  isFetching: boolean,
  byId: Object,
  // Filtered arrays of ids
  all: Array<string>,
  skating: Array<string>,
  skiing: Array<string>,
  searchResults: Array<string>
};

export const serviceSchema = new Schema('service'/*, {}*/);

Add ice skating routes to used services


(function() {
  'use strict';

  let blogTitle = document.querySelector('.blog-title');
  let titleText = document.createTextNode('Mister Mercedes');

  blogTitle.appendChild(titleText);

  let blogText = document.querySelector('.blog-text');
  let textText = document.createTextNode('Many jobless people are standing in line for a job fair when a Mercedes plows into the crowd killing 8 people and severely injuring many. Bill Hodges, a recently retired detective from the local police department living the life of a retiree, receives a letter from an individual claiming to be the person responsible for the job fair incident, referring to himself as "Mr.Mercedes".');

  setTimeout(function() {
    blogText.appendChild(textText);
  }, 3400);

  let blogDate = document.querySelector('.blog-date');
  let dateText = document.createTextNode('23 december 2017');

  setTimeout(function() {
    blogDate.appendChild(dateText);
  }, 2000);
})();

(function() {
  'use strict';

  // type of(el) - dom object
  function assignClass(el, dataObj) {
    for (let key in dataObj) {
      if (el.tagName === key) {
        el.classList.add(dataObj[key]);
      }
    }
  }

  const classesForTags = {
    'P': 'until-text',
    'IMG': 'until-img',
    'H1': 'until-title-h1',
    'H2': 'until-title-h2'
  };

  let untilLoad = document.querySelectorAll('[data-attribute="untilLoad"]');
  untilLoad = Array.prototype.slice.call(untilLoad, 0);

  untilLoad.forEach(el => {
    let untilLoadChildren = el.getElementsByTagName('*');
    untilLoadChildren = Array.prototype.slice.call(untilLoadChildren, 0);

    untilLoadChildren.forEach(el => {
      assignClass(el, classesForTags);
    });
  });
})();

(function() {
  'use strict';

  let blogTitle = document.querySelector('.blog-title');
  let titleText = document.createTextNode('Mister Mercedes');

  blogTitle.appendChild(titleText);

  let blogText = document.querySelector('.blog-text');
  let textText = document.createTextNode('Many jobless people are standing in line for a job fair when a Mercedes plows into the crowd killing 8 people and severely injuring many. Bill Hodges, a recently retired detective from the local police department living the life of a retiree, receives a letter from an individual claiming to be the person responsible for the job fair incident, referring to himself as "Mr.Mercedes".');

  setTimeout(function() {
    blogText.appendChild(textText);
  }, 3400);

  let blogDate = document.querySelector('.blog-date');
  let dateText = document.createTextNode('23 december 2017');

  setTimeout(function() {
    blogDate.appendChild(dateText);
  }, 2000);
})();

(function() {
  let untilLoad = document.querySelectorAll('[data-attribute="untilLoad"]');
  untilLoad = Array.prototype.slice.call(untilLoad, 0);
})();

Revert "add item recognition function"


import { ForbiddenException, NotFoundException, ServerErrorException } from '../../support/exceptions';
import { dbAdapter } from '../../models';

export function postAccessRequired(map = { postId: 'post' }) {
  return async (ctx, next) => {
    const forbidden = (reason = 'You can not see this post') => new ForbiddenException(reason);
    const notFound = (reason = 'Post not found') => new NotFoundException(reason);
    const { user: viewer } = ctx.state;

    await Promise.all(Object.keys(map).map(async (key) => {
      if (!ctx.params[key]) {
        throw new ServerErrorException(`Server misconfiguration: the required parameter '${key}' is missing`);
      }

      const { [key]: postId } = ctx.params;
      const post = await dbAdapter.getPostById(postId);
      const author = await dbAdapter.getUserById(post.userId);

      if (!post || !author.isActive) {
        throw notFound();
      }

      const isVisible = await post.isVisibleFor(viewer);

      if (!isVisible) {
        if (!viewer && post.isProtected === '1' && post.isPrivate === '0') {
          throw forbidden('Please sign in to view this post');
        }

        throw forbidden();
      }

      ctx.state[map[key]] = post;
    }));

    await next();
  };
}

import { ForbiddenException, NotFoundException, ServerErrorException } from '../../support/exceptions';
import { dbAdapter } from '../../models';

export function postAccessRequired(map = { postId: 'post' }) {
  return async (ctx, next) => {
    const forbidden = (reason = 'You can not see this post') => new ForbiddenException(reason);
    const notFound = (reason = 'Post not found') => new NotFoundException(reason);
    const { user: viewer } = ctx.state;

    await Promise.all(Object.keys(map).map(async (key) => {
      if (!ctx.params[key]) {
        throw new ServerErrorException(`Server misconfiguration: the required parameter '${key}' is missing`);
      }

      const { [key]: postId } = ctx.params;
      const post = await dbAdapter.getPostById(postId);
      const author = post ? await dbAdapter.getUserById(post.userId) : null;

      if (!post || !author.isActive) {
        throw notFound();
      }

      const isVisible = await post.isVisibleFor(viewer);

      if (!isVisible) {
        if (!viewer && post.isProtected === '1' && post.isPrivate === '0') {
          throw forbidden('Please sign in to view this post');
        }

        throw forbidden();
      }

      ctx.state[map[key]] = post;
    }));

    await next();
  };
}

Fix a postAccessRequired check for the case of nonexisting post


'use strict';
const ReconnectingWebSocket = require('./ReconnectingWebSocket');
const debug = require('debug')('awry:ARIWebSocket');

class ARIWebSocket extends ReconnectingWebSocket {

  emit(...args) {
    const eventIsMessage = args[0] === 'message';
    const payloadIsString = args[1] && typeof args[1] === 'string';

    if (!eventIsMessage || !payloadIsString) {
      super.emit(...args);
      return;
    }

    try {
      args[1] = JSON.parse(args[1]);
    } catch (e) {
      debug('error parsing data as JSON', args[1]);
    }

    super.emit(...args);
  }
}

module.exports = ARIWebSocket;

'use strict';
const ReconnectingWebSocket = require('./ReconnectingWebSocket');
const debug = require('debug')('awry:ARIWebSocket');

class ARIWebSocket extends ReconnectingWebSocket {

  emit(...args) {
    const eventIsMessage = args[0] === 'message';
    const payloadIsString = args[1] && typeof args[1] === 'string';

    if (!eventIsMessage || !payloadIsString) {
      super.emit(...args);
      return;
    }

    try {
      args[1] = JSON.parse(args[1]);
    } catch (e) {
      debug('error parsing data as JSON', `'${args[1]}'`, e);
    }

    super.emit(...args);
  }
}

module.exports = ARIWebSocket;

Add error to debug call on JSON parse error


/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 * @oncall relay
 */

'use strict';

import type {UserConstantDependentResolver$key} from './__generated__/UserConstantDependentResolver.graphql';

const {graphql} = require('relay-runtime');
const {readFragment} = require('relay-runtime/store/ResolverFragments');

/**
 * @RelayResolver
 * @fieldName constant_dependent
 * @rootFragment UserConstantDependentResolver
 * @onType User
 */
function constant_dependent(
  rootKey: UserConstantDependentResolver$key,
): number {
  const user = readFragment(
    graphql`
      fragment UserConstantDependentResolver on User {
        constant
      }
    `,
    rootKey,
  );
  // $FlowFixMe[prop-missing]
  constant_dependent._relayResolverTestCallCount =
    // $FlowFixMe[prop-missing]
    (constant_dependent._relayResolverTestCallCount ?? 0) + 1;
  return (user.constant ?? NaN) + 1;
}

module.exports = {
  constant_dependent,
};

/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 * @oncall relay
 */

'use strict';

import type {UserConstantDependentResolver$key} from './__generated__/UserConstantDependentResolver.graphql';

const {graphql} = require('relay-runtime');
const {readFragment} = require('relay-runtime/store/ResolverFragments');

/**
 * @RelayResolver
 * @fieldName constant_dependent
 * @rootFragment UserConstantDependentResolver
 * @onType User
 */
function constant_dependent(
  rootKey: UserConstantDependentResolver$key,
): number {
  const user = readFragment(
    graphql`
      fragment UserConstantDependentResolver on User {
        constant
      }
    `,
    rootKey,
  );
  constant_dependent._relayResolverTestCallCount =
    (constant_dependent._relayResolverTestCallCount ?? 0) + 1;
  return (user.constant ?? NaN) + 1;
}
constant_dependent._relayResolverTestCallCount = (undefined: number | void);

module.exports = {
  constant_dependent,
};

Fix some issues exposed when making function statics sealed


// Simulate config options from your production environment by
// customising the .env file in your project's root folder.
require('dotenv').config();

// Require keystone
var keystone = require('keystone');

// Initialise Keystone with your project's configuration.
// See http://keystonejs.com/guide/config for available options
// and documentation.

keystone.init({
  'name': 'Repository of Papers',
  'brand': 'Repository of Papers',

  'sass': 'public',
  'static': 'public',
  'favicon': 'public/favicon.ico',
  'views': 'templates/views',
  'view engine': 'pug',

  'auto update': true,
  'session': true,
  'auth': true,
  'user model': 'User',
});

// Load your project's Models
keystone.import('models');

// Setup common locals for your templates. The following are required for the
// bundled templates and layouts. Any runtime locals (that should be set uniquely
// for each request) should be added to ./routes/middleware.js
keystone.set('locals', {
  _: require('lodash'),
  env: keystone.get('env'),
  utils: keystone.utils,
  editable: keystone.content.editable,
});

// Load your project's Routes
keystone.set('routes', require('./routes'));

// Configure the navigation bar in Keystone's Admin UI
keystone.set('nav', {
  users: 'users',
});

// Start Keystone to connect to your database and initialise the web server
keystone.start();

// Simulate config options from your production environment by
// customising the .env file in your project's root folder.
require('dotenv').config();

// Require keystone
var keystone = require('keystone');

// Initialise Keystone with your project's configuration.
// See http://keystonejs.com/guide/config for available options
// and documentation.

keystone.init({
  'name': 'Repository of Papers',
  'brand': 'Repository of Papers',

  'sass': 'public',
  'static': 'public',
  'favicon': 'public/favicon.ico',
  'views': 'templates/views',
  'view engine': 'pug',
  'admin path': 'library',

  'auto update': true,
  'session': true,
  'auth': true,
  'user model': 'User',
});

// Load your project's Models
keystone.import('models');

// Setup common locals for your templates. The following are required for the
// bundled templates and layouts. Any runtime locals (that should be set uniquely
// for each request) should be added to ./routes/middleware.js
keystone.set('locals', {
  _: require('lodash'),
  env: keystone.get('env'),
  utils: keystone.utils,
  editable: keystone.content.editable,
});

// Load your project's Routes
keystone.set('routes', require('./routes'));

// Configure the navigation bar in Keystone's Admin UI
keystone.set('nav', {
  content: ['papers', 'authors', 'organizations'],
  users: 'users',
});

// Start Keystone to connect to your database and initialise the web server
keystone.start();

Change admin path and link layout


'use strict';

const evalString  = require('../eval-string');
const correctSSML = require('ssml-validator').correct;

module.exports = (inputText, context) => {
  if(!inputText){ return; }
  let output;
  if(typeof inputText === 'object') {
    output = evalString(inputText['en-US'], context) || '';
  } else {
    output = evalString(inputText, context) || '';
  }
  context.responseBody.outputSpeech = context.responseBody.outputSpeech || {
    type: "SSML",
    ssml: "<speak>"
  };
  output = correctSSML(output);
  context.responseBody.outputSpeech.ssml  = context.responseBody.outputSpeech.ssml.replace(/<\/speak>/, '');
  context.responseBody.outputSpeech.ssml += (`${output} </speak>` || '');
}

'use strict';

const evalString  = require('../eval-string');
const correctSSML = require('ssml-validator').correct;

module.exports = (inputText, context) => {
  if(!inputText){ return; }
  let output;
  if(typeof inputText === 'object') {
    let localizedText = inputText[context.requestBody.locale] || inputText['en-US'];
    output = evalString(localizedText, context) || '';
  } else {
    output = evalString(inputText, context) || '';
  }
  context.responseBody.outputSpeech = context.responseBody.outputSpeech || {
    type: "SSML",
    ssml: "<speak>"
  };
  output = correctSSML(output);
  context.responseBody.outputSpeech.ssml  = context.responseBody.outputSpeech.ssml.replace(/<\/speak>/, '');
  context.responseBody.outputSpeech.ssml += (`${output} </speak>` || '');
}

Add localization support for speech


/**
 * @briskhome
 * └core.log <lib/core.log/index.js>
 */

const bunyan = require('bunyan');

module.exports = function setup(options, imports, register) {
  const config = imports.config();
  const log = bunyan.createLogger({
    name: 'briskhome',
    streams: [{
      level: config.level,
      stream: process.stdout,
    }],
  });

  register(null, {
    log: () => {
      // XXX: Potential bottleneck: getting the callee from stack trace.
      const child = log.child({
        component: String(new Error().stack.split('\n')[2].split('/').slice(-2, -1)),
      });
      child.info('Initializing component');
      return child;
    },
  });
};

/**
 * @briskhome
 * └core.log <lib/core.log/index.js>
 */

const bunyan = require('bunyan');

module.exports = function setup(options, imports, register) {
  const config = imports.config();
  const log = bunyan.createLogger({
    name: 'briskhome',
    streams: [{
      level: config.level,
      stream: process.stdout,
    }],
  });

  register(null, {
    log: () => {
      // XXX: Potential bottleneck: getting the callee from stack trace.
      const child = log.child({
        component: String(new Error().stack.split('\n')[2].split('/').slice(-2, -1)),
      });
      child.debug('Initialized logger instance for component');
      return child;
    },
  });
};

Change core.log component’s child logger initialization text


var mongoose = require('mongoose');

var EventSchema = new mongoose.Schema({
    title: {type: String, trim: true},
    description: {type: String, trim: true},
    startAt: Date,
    endAt: Date,
    venue: {
        name: {type: String, trim: true},
        address: {type: String, trim: true},
        longitude: Number,
        latitude: Number
    },
    ageLimit: Number,
    price: Number,
    category: {type: String, trim: true},
    tags: [String],
    imageUrl: {type: String, trim: true},
    eventUrl: {type: String, trim: true},
    isPromoted: {type: Boolean, default: false},
    isPublished: {type: Boolean, default: false}
})

module.exports = mongoose.model('Event', EventSchema);

var mongoose = require('mongoose');

var EventSchema = new mongoose.Schema({
    title: {type: String, trim: true},
    description: {type: String, trim: true},
    startAt: Date,
    endAt: Date,
    venue: {
        name: {type: String, trim: true},
        address: {type: String, trim: true},
        longitude: Number,
        latitude: Number
    },
    ageLimit: Number,
    price: Number,
    category: {type: String, trim: true},
    tags: [String],
    imageUrl: {type: String, trim: true},
    eventUrl: {type: String, trim: true},
    isPromoted: {type: Boolean, default: false},
    isPublished: {type: Boolean, default: false}
}, {timestamps: true})

module.exports = mongoose.model('Event', EventSchema);

Add timestamps (created/updated) to event schema


import loop from 'loop';
import { render as renderUI, uiElements, clearUi } from 'ui';
import { clear } from 'pura/canvas/tuple';
import { subtractSet } from 'pura/vector/tuple';
import state from 'state';
import { Dialog } from 'dialog';
import { render as renderGraphics } from 'overworld/graphics';
import logic, { avngSprite } from 'overworld/logic';
import { calcWorldPosition } from 'camera';
import { canvasOffsetLeft, canvasOffsetTop, scaleX, scaleY } from 'dom';

let stopLoop;

const calcMousePosition =
  ({ clientX, clientY, touches }) =>
    touches
      ? ([touches[0].clientX, touches[0].clientY])
      : ([clientX, clientY]);

let moveTo;
const evtMouseDown = (e)=> (moveTo = e);
const evtMouseMove = (e)=> moveTo && (moveTo = e);
const evtMouseUp = ()=> (moveTo = false);

export default {
  init: () => {
    uiElements.push(Dialog);
    state.logic = (dt) => {
      // Logic
      logic(dt);
      renderGraphics(dt);
      // Input
      if (moveTo) {
        const position = subtractSet(calcMousePosition(moveTo), [canvasOffsetLeft, canvasOffsetTop]);
        position[0] *= scaleX;
        position[1] *= scaleY;
        state.target = calcWorldPosition(position);
      }
    };

    window.addEventListener(`mousedown`, evtMouseDown);
    window.addEventListener(`mousemove`, evtMouseMove);
    window.addEventListener(`mouseup`, evtMouseUp);
  },
  dismiss: () => {
    window.removeEventListener(`mousedown`, evtMouseDown);
    window.removeEventListener(`mousemove`, evtMouseMove);
    window.removeEventListener(`mouseup`, evtMouseUp);
  },
};

import loop from 'loop';
import { render as renderUI, uiElements, clearUi } from 'ui';
import { clear } from 'pura/canvas/tuple';
import { subtractSet } from 'pura/vector/tuple';
import state from 'state';
import { Dialog } from 'dialog';
import { inputs } from 'controls';
import { render as renderGraphics } from 'overworld/graphics';
import logic, { avngSprite } from 'overworld/logic';
import { calcWorldPosition } from 'camera';
import { canvasOffsetLeft, canvasOffsetTop, scaleX, scaleY } from 'dom';

export default {
  init: () => {
    uiElements.push(Dialog);
    state.logic = (dt) => {
      // Logic
      logic(dt);
      renderGraphics(dt);
      // Input
      if (inputs.click) {
        state.target = calcWorldPosition(inputs.mousePosition);
      }
    };
  },
  dismiss: () => { },
};

Update with new input controls


import Ember from 'ember';

export default Ember.View.extend({
    tagName: 'input',
    type: 'radio',
    attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name'],

    htmlChecked: function() {
        return this.get('value') === this.get('checked');
    }.property('value', 'checked'),

    change: function() {
        this.set('checked', this.get('value'));
    },

    _updateElementValue: function() {
        Ember.run.next(this, function() {
          this.$().prop('checked', this.get('htmlChecked'));
        });
    }.observes('htmlChecked')
});

import Ember from 'ember';

export default Ember.View.extend({
    tagName: 'input',
    type: 'radio',
    attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name', 'disabled'],

    htmlChecked: function() {
        return this.get('value') === this.get('checked');
    }.property('value', 'checked'),

    change: function() {
        this.set('checked', this.get('value'));
    },

    _updateElementValue: function() {
        Ember.run.next(this, function() {
          this.$().prop('checked', this.get('htmlChecked'));
        });
    }.observes('htmlChecked')
});

Add support for the `disabled` attribute on radio inputs.


#! /usr/bin/env node

var request = require('request');

request('http://drizzy-server.herokuapp.com/lyric', function (error, response, body) {
  console.log('error:', error); // Print the error if one occurred
  console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
  console.log('body:', body); // Print the HTML for the Google homepage.
});

#! /usr/bin/env node
'use strict';
var request = require('request');

const DRIZZY_API = 'http://drizzy-server.herokuapp.com'

request(DRIZZY_API + '/lyric', function (error, response, body) {
  console.log(body);
});

Remove error and statusCode output


// Command-line arguments passed to npm when rebuilding binary packages.
var args = [
  "rebuild",

  // The --no-bin-links flag tells npm not to create symlinks in the
  // node_modules/.bin/ directory when rebuilding packages, which helps
  // avoid problems like https://github.com/meteor/meteor/issues/7401.
  "--no-bin-links",

  // The --update-binary flag tells node-pre-gyp to replace previously
  // installed local binaries with remote binaries:
  // https://github.com/mapbox/node-pre-gyp#options
  "--update-binary"
];

// Allow additional flags to be passed via the $METEOR_NPM_REBUILD_FLAGS
// environment variable.
var flags = process.env.METEOR_NPM_REBUILD_FLAGS;
if (flags) {
  args.push.apply(args, flags.split(/\s+/g));
}

exports.get = function () {
  // Make a defensive copy.
  return args.slice(0);
};

// Command-line arguments passed to npm when rebuilding binary packages.
var args = [
  "rebuild",

  // The --no-bin-links flag tells npm not to create symlinks in the
  // node_modules/.bin/ directory when rebuilding packages, which helps
  // avoid problems like https://github.com/meteor/meteor/issues/7401.
  "--no-bin-links",

  // The --update-binary flag tells node-pre-gyp to replace previously
  // installed local binaries with remote binaries:
  // https://github.com/mapbox/node-pre-gyp#options
  "--update-binary"
];

// Allow additional flags to be passed via the $METEOR_NPM_REBUILD_FLAGS
// environment variable.
var flags = process.env.METEOR_NPM_REBUILD_FLAGS;
if (flags) {
  args = ["rebuild"];
  flags.split(/\s+/g).forEach(function (flag) {
    if (flag) {
      args.push(flag);
    }
  });
}

exports.get = function () {
  // Make a defensive copy.
  return args.slice(0);
};

Make $METEOR_NPM_REBUILD_FLAGS override default flags.


var self = window.Flow;
window.Flow.FlowChunk.prototype.getParams = function () {
    return {
      // flowChunkNumber: this.offset + 1,
      // flowChunkSize: this.flowObj.opts.chunkSize,
      // flowCurrentChunkSize: this.endByte - this.startByte,
      // flowTotalSize: this.fileObjSize,
      // flowIdentifier: this.fileObj.uniqueIdentifier,
      // flowFilename: this.fileObj.name,
      // flowRelativePath: this.fileObj.relativePath,
      // flowTotalChunks: this.fileObj.chunks.length,
      compressionMode: 'NORMAL',
      compressionSize: this.fileObjSize,
      originalSize: this.fileObjSize,
      content: 'Blah Blah'
    };
};

var self = window.Flow;
window.Flow.FlowChunk.prototype.getParams = function () {
    return {
      // flowChunkNumber: this.offset + 1,
      // flowChunkSize: this.flowObj.opts.chunkSize,
      // flowCurrentChunkSize: this.endByte - this.startByte,
      // flowTotalSize: this.fileObjSize,
      // flowIdentifier: this.fileObj.uniqueIdentifier,
      // flowFilename: this.fileObj.name,
      // flowRelativePath: this.fileObj.relativePath,
      // flowTotalChunks: this.fileObj.chunks.length,
      compressionMode: 'NORMAL',
      compressionSize: 0,
      originalSize: this.fileObjSize,
      content: 'Blah Blah'
    };
};

Change to 0 for compressionSize


export let baseUrl = 'http://rosettastack.com';
export let sites = [{
  name: 'Programmers',
  slug: 'programmers',
  seUrl: 'http://programmers.stackexchange.com/',
  langs: ['en', 'fr'],
  db: 'localhost/stackview-db',
}];

export let baseUrl = 'http://rosettastack.com';
export let sites = [{
  name: 'Programmers',
  slug: 'programmers',
  seUrl: 'http://programmers.stackexchange.com/',
  langs: ['en', 'fr'],
  db: 'localhost/programmers',
}, {
  name: 'Coffee',
  slug: 'coffee',
  seUrl: 'http://coffee.stackexchange.com/',
  langs: ['en', 'fr'],
  db: 'localhost/coffee',
}, {
  name: 'ServerFault',
  slug: 'serverfault',
  seUrl: 'http://serverfault.com/',
  langs: ['en', 'fr'],
  db: 'localhost/serverfault',
}];

Add a couple more test sites


var dataSource = function () {
    var module = {};

    module.load = function (url, callback) {
        d3.json(url, function (error, data) {
            if (error) return console.warn(error);

            callback(data);
        });
    };

    module.loadCSV = function (url, callback) {
        d3.csv(url, function (error, data) {
            if (error) return console.warn(error);

            callback(data);
        });
    };

    return module;
}();

var dataSource = function () {
    var module = {};

    var loadHandlersByType = {};

    var loadHandlers = function (type) {
        loadHandlersByType[type] = loadHandlersByType[type] || {};
        return loadHandlersByType[type];
    };

    var load = function (type, url, handler) {
        var handlers = loadHandlers(type)[url] || [];
        handlers.push(handler);
        loadHandlers(type)[url] = handlers;

        if (handlers.length === 1) {
            if (type === 'json') {
                d3.json(url, function (error, data) {
                    callbackHandlers(type, url, error, data);
                });
            } else {
                d3.csv(url, function (error, data) {
                    callbackHandlers(type, url, error, data);
                });
            }
        }
    };

    var callbackHandlers = function (type, url, error, data) {
        var handlers = loadHandlers(type)[url];
        loadHandlers(type)[url] = undefined;

        if (error) {
            console.warn(error);
        } else {
            handlers.forEach(function (handler) {
                handler(data);
            });
        }
    };

    module.load = function (url, callback) {
        load('json', url, callback);
    };

    module.loadCSV = function (url, callback) {
        load('csv', url, callback);
    };

    return module;
}();

Load same resources only once per page load, works around Firefox sending second request without cache headers, eases load on the server and improves loading speed


import { defaults, isArray, map, mapValues } from 'lodash'

export function flattenChangesetValues(changeset) {
  const result = defaults({}, changeset.changes, changeset.data)

  return mapValues(result, value => {
    if (isChangeset(value)) {
      return flattenChangesetValues(value)
    }

    if (isArray(value)) {
      return map(value, item => {
        return isChangeset(item) ? flattenChangesetValues(item) : item
      })
    }

    return value
  })
}

function isChangeset(object) {
  return !!object && !!object.data && !!object.changes
}

import { defaults, isArray, map, mapValues } from 'lodash'

/**
 * Merges an Ecto changeset's `changes` and `data` values into a
 * single values object, preferring `changes` (changed values) over
 * `data` (original values) if present. This is done recursively
 * for nested changesets as well.
 *
 * @param {Object} changeset
 */
export function flattenChangesetValues(changeset) {
  const result = defaults({}, changeset.changes, changeset.data)

  return mapValues(result, value => {
    if (isChangeset(value)) {
      return flattenChangesetValues(value)
    }

    if (isArray(value)) {
      return map(value, item => {
        return isChangeset(item) ? flattenChangesetValues(item) : item
      })
    }

    return value
  })
}

function isChangeset(object) {
  return !!object && !!object.data && !!object.changes
}

Add docs for JS changeset utilitities


/* global describe, it */

import {exec} from '../../../src/utils/util';
import assert from 'assert';
require('chai').should();

describe("Oi CLI", () => {

  it("can be invoked", () => {
    const result = exec('node dist/bin/oi.js -v');
    console.log(result);
    console.log(result.toString());
    console.log(result.code);
    console.log(result.stdout);
    console.log(result.stdout.trim());
    console.log(result.stdout.trim().match(/^\d+\.\d+\.\d+$/));
    result.stdout.trim().should.match(/^\d+\.\d+\.\d+$/);
  });

});

/* global describe, it */

import {exec} from '../../../src/utils/util';
import assert from 'assert';
require('chai').should();

describe("Oi CLI", () => {

  it("can be invoked", () => {
    const result = exec('node dist/bin/oi.js -v');
    console.log(result);
    console.log(result.toString());
    console.log(result.code);
    console.log(result.stdout);
    console.log(result.stdout.trim());
    console.log(result.stdout.trim().match(/^\d+\.\d+\.\d+$/));
    try {
      result.stdout.trim().should.match(/^\d+\.\d+\.\d+$/);
    } catch (e) {
      console.error('ERROR:', e);
      throw Error('FAIL');
    }
  });

});

Add try catch to investigate other errors


import Ember from 'ember';

import DocumentTitle from "ember-document-title/mixins/document-title";

DocumentTitle.reopen({
    "titleSpecificityIncreases": false,
    "titleDivider": "-"
});

export default {
  name: "document-title-config",
  initialize: function () {}
};

Remove unused 'Ember' import in title config


import { show, hide } from '@utils';

export function showMotivation(event, state) {
  event.preventDefault();
  show(document.querySelector(`.motivation.${state}`));
  hide(document.querySelector('.dropdown-items'));
}

export function motivationCancel() {
  document.querySelectorAll('.motivation').forEach(hide);
  show(document.querySelector('.dropdown-items'));
}

import { show, hide } from '@utils';

export function showMotivation(event, state) {
  event.preventDefault();
  motivationCancel();
  show(document.querySelector(`.motivation.${state}`));
  hide(document.querySelector('.dropdown-items'));
}

export function motivationCancel() {
  document.querySelectorAll('.motivation').forEach(hide);
  show(document.querySelector('.dropdown-items'));
}

Hide other motivation fields when switching between states


import React from "react";
import { FormGroup, Label, Input } from "reactstrap";

export default ({ updateArgs = () => {}, args, client }) => {
  const lrmText = e => {
    let value = e.target.value;
    const regex = /.*(?= out| out\.)/gi;
    const match = value.match(regex);
    if (match) {
      setTimeout(() => {
        updateArgs("sender", match[match.length - 2]);
      }, 100);
    }
    updateArgs("message", value);
  };
  const updateSender = e => {
    updateArgs("sender", e.target.value);
  };
  if (!args || !args.crew) {
    updateArgs("crew", true);
  }
  return (
    <FormGroup className="macro-sendLongRangeMessage">
      Sender
      <Input
        type="text"
        value={args ? args.sender : ""}
        onChange={updateSender}
      />

        Message{" "}
        Use #SIM in your message for the name of the simulator

      <Input
        type="textarea"
        defaultValue={args ? args.message : ""}
        onBlur={lrmText}
      />
    </FormGroup>
  );
};

import React from "react";
import { FormGroup, Label, Input, Button, ButtonGroup } from "reactstrap";

export default ({ updateArgs = () => {}, args, client }) => {
  const lrmText = e => {
    let value = e.target.value;
    const regex = /.*(?= out| out\.)/gi;
    const match = value.match(regex);
    if (match) {
      setTimeout(() => {
        updateArgs("sender", match[match.length - 2]);
      }, 100);
    }
    updateArgs("message", value);
  };
  const updateSender = e => {
    updateArgs("sender", e.target.value);
  };
  // if (!args || !args.crew) {
  //   updateArgs("crew", true);
  // }
  console.log(args);
  return (
    <FormGroup className="macro-sendLongRangeMessage">
      Inbound/Outbound

        <ButtonGroup>
          <Button
            onClick={() => updateArgs("crew", true)}
            active={args ? args.crew : true}
          >
            Inbound
          </Button>
          <Button
            onClick={() => updateArgs("crew", false)}
            active={args ? !args.crew : false}
          >
            Outbound
          </Button>
        </ButtonGroup>

      Sender
      <Input
        type="text"
        value={args ? args.sender : ""}
        onChange={updateSender}
      />

        Message{" "}
        Use #SIM in your message for the name of the simulator

          If message is outbound, be sure to include{" "}
          {`"To: <message location>"`} at the top of the message.

      <Input
        rows={4}
        type="textarea"
        defaultValue={args ? args.message : ""}
        onBlur={lrmText}
      />
    </FormGroup>
  );
};

Update send long range message timeline item to support sending messages from within the ship.


/**
 * User: powerumc
 * Date: 2014. 5. 18.
 * Time: ������ 8:39
 */

$(function() {
	$(function () {
		$.ajax({
			url: "README.md",
			type: "GET",
			success: function (data) {
				var html = marked(data);
				$("#preview").html(html);

				var toc = $("#toc").tocify({
					context: "#preview",
					selectors: "h1, h2, h3, h4, h5, h6",
					showEffect: "slideDown",
					hideEffect: "slideUp",
					theme: "jqueryui",
					hashGenerator: "pretty",
					highlightOffset: 40});

				$("code").addClass("prettyprint");

				prettyPrint();

				$(document).ready(function () {
					$('[data-toggle=offcanvas]').click(function () {
						$('.row-offcanvas').toggleClass('active');
					});
				});

				$("#title").text($("#preview h1:first").text());
			}
		});
	});

});

/**
 * User: powerumc
 * Date: 2014. 5. 18.
 */

$(function() {
	$(function () {
		$.ajax({
			url: "README.md",
			type: "GET",
			success: function (data) {
				var html = marked(data);
				$("#preview").html(html);

				var toc = $("#toc").tocify({
					context: "#preview",
					selectors: "h1, h2, h3, h4, h5, h6",
					showEffect: "slideDown",
					hideEffect: "slideUp",
					scrollTo: 55,
					theme: "jqueryui",
					hashGenerator: "pretty",
					highlightOffset: 40});

				$("code").addClass("prettyprint");

				prettyPrint();

				$(document).ready(function () {
					$('[data-toggle=offcanvas]').click(function () {
						$('.row-offcanvas').toggleClass('active');
					});
				});

				$("#title").text($("#preview h1:first").text());
			}
		});
	});

});

Set tocify scrollTo property to offset top banner


//= require openseadragon

(function($) {
  var __osd_counter = 0;
  function generateOsdId() {
    __osd_counter++;

    return "Openseadragon" + __osd_counter;
  }

  function initOpenSeadragon() {
    $('picture[data-openseadragon]').each(function() {
      var $picture = $(this);

      if (typeof $picture.attr('id') === "undefined") {
        $picture.attr('id', generateOsdId());
      }

      var collectionOptions = $picture.data('openseadragon');

      var sources = $picture.find('source[media="openseadragon"]');

      var tilesources = $.map(sources, function(e) {
        if ($(e).data('openseadragon')) {
          return $(e).data('openseadragon');
        } else {
          return $(e).attr('src');
        }
      });

      $picture.css("display", "block");
      $picture.css("height", "500px");

      $picture.data('osdViewer', OpenSeadragon(
        $.extend({ id: $picture.attr('id') }, collectionOptions, { tileSources: tilesources })
      ));
    });
  };

  window.onload = initOpenSeadragon;
  document.addEventListener("page:load", initOpenSeadragon);
})(jQuery);

//= require openseadragon

(function($) {
  var __osd_counter = 0;
  function generateOsdId() {
    __osd_counter++;

    return "Openseadragon" + __osd_counter;
  }

  function initOpenSeadragon() {
    $('picture[data-openseadragon]').each(function() {
      var $picture = $(this);

      if (typeof $picture.attr('id') === "undefined") {
        $picture.attr('id', generateOsdId());
      }

      var collectionOptions = $picture.data('openseadragon');

      var sources = $picture.find('source[media="openseadragon"]');

      var tilesources = $.map(sources, function(e) {
        if ($(e).data('openseadragon')) {
          return $(e).data('openseadragon');
        } else {
          return $(e).attr('src');
        }
      });

      $picture.css("display", "block");
      $picture.css("height", "500px");

      $picture.data('osdViewer', OpenSeadragon(
        $.extend({ id: $picture.attr('id') }, collectionOptions, { tileSources: tilesources })
      ));
    });
  };

  window.onload = initOpenSeadragon;
  document.addEventListener("page:load", initOpenSeadragon, false);
})(jQuery);

Add 3rd parameter to addEventListener for backwards browser compatibility.


var utils = require('shipit-utils');

/**
 * Symfony tasks
 */

module.exports = function (gruntOrShipit) {
  require('./vendors')(gruntOrShipit);
  require('./cache')(gruntOrShipit);
  require('./assets')(gruntOrShipit);

  utils.registerTask(gruntOrShipit, 'symfony:install', [
    'symfony:cache',
    'symfony:assets'
  ]);

  var shipit = utils.getShipit(gruntOrShipit);

  // Install vendors locally
  shipit.on('fetched', function() {
    shipit.start('symfony:vendors');
  });

  shipit.on('start', function() {
    // Prepare new release on server before publish
    var event = shipit.config.symfony.installOn || 'updated'; // or 'sharedEnd'
    shipit.on(event, function() {
      shipit.start('symfony:install');
    });
  });
};

var utils = require('shipit-utils');

/**
 * Symfony tasks
 */

module.exports = function (gruntOrShipit) {
  require('./vendors')(gruntOrShipit);
  require('./cache')(gruntOrShipit);
  require('./assets')(gruntOrShipit);

  utils.registerTask(gruntOrShipit, 'symfony:install', [
    'symfony:cache',
    'symfony:assets'
  ]);

  var shipit = utils.getShipit(gruntOrShipit);

  // Install vendors locally
  shipit.on('fetched', function() {
    shipit.start('symfony:vendors');
  });

  shipit.on('start', function() {
    // Prepare new release on server before publish
    var event = shipit.config.symfony.installOn;
    event = event !== undefined ? event : 'updated'; // or 'sharedEnd'
    shipit.on(event, function() {
      shipit.start('symfony:install');
    });
  });
};

Fix case where installOn is undefined


function on(nm, cb, capture) {
  this.each(function(el) {
    el.addEventListener(nm, cb, capture);
  });
  return this;
}

function off(nm, cb, capture) {
  this.each(function(el) {
    el.removeEventListener(nm, cb, capture);
  });
  return this;
}

function trigger(event, bubbles, cancelable, group) {
  bubbles = typeof(bubbles) === undefined ? true : bubbles;
  cancelable = typeof(cancelable) === undefined ? true : cancelable;
  type = type || 'HTMLEvents';
  this.each(function(el) {
    if(document.createEvent) {
      // dispatch for firefox + others
      var evt = document.createEvent("HTMLEvents");
      // event type,bubbling,cancelable
      evt.initEvent(event, bubbles, cancelable);
      return !el.dispatchEvent(evt);
    }else{
      // dispatch for IE
      var evt = document.createEventObject();
      return el.fireEvent('on' + event, evt)
    }
  });
}

function click(bubbles, cancelable) {
  return this.trigger('click', bubbles, cancelable, 'MouseEvents');
}

module.exports = function() {
  this.on = on;
  this.off = off;
  this.trigger = trigger;
  this.click = click;
}

function on(nm, cb, capture) {
  this.each(function(el) {
    el.addEventListener(nm, cb, capture);
  });
  return this;
}

function off(nm, cb, capture) {
  this.each(function(el) {
    el.removeEventListener(nm, cb, capture);
  });
  return this;
}

function trigger(event, bubbles, cancelable, type) {
  bubbles = typeof(bubbles) === undefined ? true : bubbles;
  cancelable = typeof(cancelable) === undefined ? true : cancelable;
  type = type || 'HTMLEvents';
  this.each(function(el) {
    if(document.createEvent) {
      // dispatch for firefox + others
      var evt = document.createEvent("HTMLEvents");
      // event type,bubbling,cancelable
      evt.initEvent(event, bubbles, cancelable);
      return !el.dispatchEvent(evt);
    }else{
      // dispatch for IE
      var evt = document.createEventObject();
      return el.fireEvent('on' + event, evt)
    }
  });
}

function click(bubbles, cancelable) {
  return this.trigger('click', bubbles, cancelable, 'MouseEvents');
}

module.exports = function() {
  this.on = on;
  this.off = off;
  this.trigger = trigger;
  this.click = click;
}

Fix typo in trigger() arguments.


// @ts-check

import typescript from 'rollup-plugin-typescript2';
import uglify from 'rollup-plugin-uglify';
import gzip from 'rollup-plugin-gzip';
import filesize from 'rollup-plugin-filesize';

const __PROD__ = process.env.NODE_ENV === 'production';

function outputFileName() {
  let fileName = `react-form-with-constraints.${process.env.NODE_ENV}`;
  fileName += __PROD__ ? '.min.js' : '.js';
  return fileName;
}

export default {
  input: './src/index.ts',
  output: {
    file: `dist/${outputFileName()}`,
    name: 'ReactFormWithConstraints',
    format: 'umd',
    sourcemap: true
  },

  external: ['react', 'react-dom', 'prop-types'],
  globals: {
    react: 'React',
    'react-dom': 'ReactDOM',
    'prop-types': 'PropTypes'
  },

  plugins: [
    typescript({
      abortOnError: false,
      clean: true,
      tsconfigOverride: {compilerOptions: {module: 'esnext', declaration: false}}
    }),
    __PROD__ && uglify(),
    gzip({algorithm: 'zopfli'}),
    filesize()
  ]
};

// @ts-check

import typescript from 'rollup-plugin-typescript2';
import uglify from 'rollup-plugin-uglify';
import gzip from 'rollup-plugin-gzip';
import filesize from 'rollup-plugin-filesize';

const __PROD__ = process.env.NODE_ENV === 'production';

function outputFileName() {
  let fileName = `react-form-with-constraints.${process.env.NODE_ENV}`;
  fileName += __PROD__ ? '.min.js' : '.js';
  return fileName;
}

export default {
  input: './src/index.ts',
  output: {
    file: `dist/${outputFileName()}`,
    name: 'ReactFormWithConstraints',
    format: 'umd',
    sourcemap: true
  },

  external: ['react', 'react-dom', 'prop-types'],
  globals: {
    react: 'React',
    'react-dom': 'ReactDOM',
    'prop-types': 'PropTypes'
  },

  plugins: [
    typescript({
      abortOnError: false,
      clean: true,
      tsconfigOverride: {compilerOptions: {module: 'esnext', declaration: false, removeComments: true}}
    }),
    __PROD__ && uglify(),
    gzip({algorithm: 'zopfli'}),
    filesize()
  ]
};

Remove the comments from the generated UMD files


const utils = require('../lib/utils')
const insecurity = require('../lib/insecurity')
const models = require('../models/index')
const challenges = require('../data/datacache').challenges

module.exports = function retrieveBasket () {
  return (req, res, next) => {
    const id = req.params.id
    models.Basket.findOne({ where: { id }, include: [{ model: models.Product, paranoid: false }] })
      .then(basket => {
        /* jshint eqeqeq:false */
        if (utils.notSolved(challenges.basketAccessChallenge)) {
          const user = insecurity.authenticatedUsers.from(req)
          if (user && id && id !== 'undefined' && id !== 'null' && user.bid != id) { // eslint-disable-line eqeqeq
            utils.solve(challenges.basketAccessChallenge)
          }
        }
        if (basket.Products && basket.Products.length > 0) {
          for (let i = 0; i < basket.Products.length; i++) {
            basket.Products[i].name = req.__(basket.Products[i].name)
          }
        }
        res.json(utils.queryResultToJson(basket))
      }).catch(error => {
        next(error)
      })
  }
}

const utils = require('../lib/utils')
const insecurity = require('../lib/insecurity')
const models = require('../models/index')
const challenges = require('../data/datacache').challenges

module.exports = function retrieveBasket () {
  return (req, res, next) => {
    const id = req.params.id
    models.Basket.findOne({ where: { id }, include: [{ model: models.Product, paranoid: false }] })
      .then(basket => {
        /* jshint eqeqeq:false */
        if (utils.notSolved(challenges.basketAccessChallenge)) {
          const user = insecurity.authenticatedUsers.from(req)
          if (user && id && id !== 'undefined' && id !== 'null' && user.bid != id) { // eslint-disable-line eqeqeq
            utils.solve(challenges.basketAccessChallenge)
          }
        }
        if (basket && basket.Products && basket.Products.length > 0) {
          for (let i = 0; i < basket.Products.length; i++) {
            basket.Products[i].name = req.__(basket.Products[i].name)
          }
        }
        res.json(utils.queryResultToJson(basket))
      }).catch(error => {
        next(error)
      })
  }
}

Fix potential null pointer during product translation


'use strict';

var Bluebird = require('bluebird');
var _path    = require('path');
var redefine = require('redefine');

module.exports = redefine.Class({
  constructor: function(path, options) {
    this.path    = _path.resolve(path);
    this.file    = _path.basename(this.path);
    this.options = options;
   },

  migration: function () {
    return require(this.path);
  },

  up: function () {
    return this._exec('up', arguments);
  },

  down: function () {
    return this._exec('down', arguments);
  },

  testFileName: function (needle) {
    return this.file.indexOf(needle) === 0;
  },

  _exec: function (method, args) {
    var migration = this.migration();
    return (migration[method] || Bluebird.resolve).apply(migration, args);
  }
});

'use strict';

var Bluebird = require('bluebird');
var _path    = require('path');
var redefine = require('redefine');

module.exports = redefine.Class({
  constructor: function(path, options) {
    this.path    = _path.resolve(path);
    this.file    = _path.basename(this.path);
    this.options = options;
   },

  migration: function () {
    return require(this.path);
  },

  up: function () {
    return this._exec('up', [].slice.apply(arguments));
  },

  down: function () {
    return this._exec('down', [].slice.apply(arguments));
  },

  testFileName: function (needle) {
    return this.file.indexOf(needle) === 0;
  },

  _exec: function (method, args) {
    var migration = this.migration();
    return (migration[method] || Bluebird.resolve).apply(migration, args);
  }
});

Transform args into proper arrays


document.getElementById("ayuda").setAttribute("aria-current", "page");

var aside = document.getElementById("complementario");
var button = document.createElement("BUTTON");
var text = document.createTextNode("Prueba");
button.appendChild(text);
aside.appendChild(button);
var div = document.createElement("DIV");

function prueba() {
		var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
		if (this.readyState == 4 && this.status == 200) {
			// document.getElementById("demo").innerHTML = this.responseText;
			alert("hecho");
		}
	};
	xhttp.open("GET", "https://api.github.com/repos/nvdaes/placeMarkers/releases/latest", true);
	xhttp.send();
}

button.addEventListener("click", prueba, true);

document.getElementById("ayuda").setAttribute("aria-current", "page");

var aside = document.getElementById("complementario");
var button = document.createElement("BUTTON");
var text = document.createTextNode("Información sobre placeMarkers");
button.appendChild(text);
aside.appendChild(button);
var div = document.createElement("DIV");

function showAddonInfo(addon) {
		var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
		if (this.readyState == 4 && this.status == 200) {
			var div.createElement("DIV");
			var json = JSON.parse(xhttp.responseText);
			div.innerHTML = json.name;
		}
	};
	xhttp.open("GET", "https://api.github.com/repos/nvdaes/" + addon + "/releases/latest", true);
	xhttp.send();
}

function showPlaceMarkersInfo() {
	showAddonInfo("placeMarkers");
}

button.addEventListener("click", showPlaceMarkersInfo, true);

Test with real example of AJAX


function runTests(testType, BABYLON, GUI, INSPECTOR) {

    console.log("running tests");

    describe(testType + ' module tests', function () {

        it("should have the dependencies loaded", function () {
            assert.isDefined(BABYLON);
            assert.isDefined(GUI);
            assert.isDefined(INSPECTOR);
            assert.isDefined(BABYLON.GLTF2);
        })

        var subject;

        /**
         * Create a nu engine subject before each test.
         */
        beforeEach(function () {
            subject = new BABYLON.NullEngine({
                renderHeight: 256,
                renderWidth: 256,
                textureSize: 256,
                deterministicLockstep: false,
                lockstepMaxSteps: 1
            });
        });
        /**
         * This test is more an integration test than a regular unit test but highlights how to rely
         * on the BABYLON.NullEngine in order to create complex test cases.
         */
        describe('#GLTF', function () {
            it('should load BoomBox GLTF', function (done) {
                mocha.timeout(10000);
                var scene = new BABYLON.Scene(subject);
                BABYLON.SceneLoader.Append("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene, function () {
                    scene.meshes.length.should.be.equal(2);
                    scene.materials.length.should.be.equal(1);
                    scene.multiMaterials.length.should.be.equal(0);
                    done();
                });
            });
        });
    });
}

function runTests(testType, BABYLON, GUI, INSPECTOR) {

    console.log("running tests");

    describe(testType + ' module tests', function () {

        it("should have the dependencies loaded", function () {
            assert.isDefined(BABYLON, "BABYLON should be defined");
            assert.isDefined(GUI, "GUI should be defined");
            assert.isDefined(INSPECTOR, "INSPECTOR should be defined");
            // GLTF2 has migrated to BABYLON
            // assert.isDefined(BABYLON.GLTF2, "BABYLON.GLTF2 should be defined");
        })

        var subject;

        /**
         * Create a nu engine subject before each test.
         */
        beforeEach(function () {
            subject = new BABYLON.NullEngine({
                renderHeight: 256,
                renderWidth: 256,
                textureSize: 256,
                deterministicLockstep: false,
                lockstepMaxSteps: 1
            });
        });
        /**
         * This test is more an integration test than a regular unit test but highlights how to rely
         * on the BABYLON.NullEngine in order to create complex test cases.
         */
        describe('#GLTF', function () {
            it('should load BoomBox GLTF', function (done) {
                mocha.timeout(10000);
                var scene = new BABYLON.Scene(subject);
                BABYLON.SceneLoader.Append("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene, function () {
                    scene.meshes.length.should.be.equal(2);
                    scene.materials.length.should.be.equal(1);
                    scene.multiMaterials.length.should.be.equal(0);
                    done();
                });
            });
        });
    });
}

Fix tests issues with namespaces changes


var config = {
  production : {
    port : 80,
    serviceURL : 'http://wapm-service.jit.su'
  },
  development : {
    port : 9000,
    serviceURL : 'http://wapm-service.jit.su'
    //serviceURL : 'http://localhost:8000'
  },
  test : {
    port : 9000
  }
};

module.exports = config[ process.env.NODE_ENV || 'development' ];

var config = {
  production : {
    port : 9000,
    serviceURL : 'http://wapm-service.jit.su'
  },
  development : {
    port : 9000,
    serviceURL : 'http://wapm-service.jit.su'
    //serviceURL : 'http://localhost:8000'
  },
  test : {
    port : 9000
  }
};

module.exports = config[ process.env.NODE_ENV || 'development' ];

Use port > 1024 in production to avoid ECONNREFUSED error