<commit_before>/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.l = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}

/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// identity function for calling harmony imports with the correct context
/******/ 	__webpack_require__.i = function(value) { return value; };

/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};

/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};

/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Componentizer {
    constructor() {
        this.components = {};
    }
    // createRecorder(actions, view = ()=>{}) {
    //     let path = window.location.pathname;
    //     let model = {
    //         pageLoadTimestamp: Date.now(),
    //         steps: [],
    //         components: {},
    //         recording: true,
    //         sessionName: path.substr(1, path.indexOf('.')-1).split('/').join('_')
    //     };
    //     this.recorder = new Componentizer.Component("recorder", actions, view, model);
    // }

    create(componentName, actions, view = ()=>{}, model = {}) {
        this.components[componentName] = new Componentizer.Component(componentName, actions, view, model);
    }
}

Componentizer.Component = class {
    constructor (componentName, actions, view, model) {
        if (componentName == null || componentName === "") {
            throw new Error("Your component needs a name");
        }

        if (actions == null) {
            const example = "// It must be a function that takes a model and returns an object of functions, e.g.\r\n\r\nYourComponent.Actions = function (model) {\r\n    return {\r\n        sayHello: () { console.log('Hi.'); },\r\n        greet: (name) { console.log('Hello, ' + name); }\r\n    }\r\n}";
            throw new Error(`${componentName} needs some actions! Here's an example of an Actions function:\r\n\r\n${example}\r\n\r\n`);
        }

        this.componentName = componentName;

        let _view = view && view();
        let viewInit = _view && _view.init ? _view.init : () => {};
        let render = _view && _view.render ? _view.render : () =>{};

        Object.assign(this, this.componentize(actions(model), render, model));
        viewInit(this, model);

        // if (componentizer.recorder && componentName !== "recorder") {
        //     componentizer.recorder.storeComponent(this, model);
        // }
    }

    componentize(actions, render, model) {
        render(model);
        let component = {};
        Object.keys(actions).map((action) => {
            component[action] = (...args) => {

                let returnValue = actions[action].apply(actions, args);

                // if (componentizer.recorder && componentName !== "recorder" && componentizer.recorder.get("recording")) {
                //     componentizer.recorder.recordStep(componentName, model, action, args);
                // }

                if (returnValue && returnValue.then) {
                    this.handlePromise(returnValue, render);
                }
                render(model);
            }
        }, this);
        component.get = (prop) => model[prop];
        return component;
    }

    handlePromise(promise, render) {
        promise
            .then((updatedModel)=> {
                if (updatedModel == null) {
                    throw new Error("No model received: aborting render");
                }
                render(updatedModel);
            })
            .catch((err) => {
                if (typeof err === "string") {
                    console.error(err);
                } else {
                    console.error(`Error unhandled by component. Add a catch handler to your AJAX method.`);
                }
            });
    }
}

const comp = new Componentizer();
Object.freeze(comp);

/* harmony default export */ exports["default"] = comp;

/***/ }
/******/ ]);<commit_msg>Added unit tests<commit_after>/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.l = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}

/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// identity function for calling harmony imports with the correct context
/******/ 	__webpack_require__.i = function(value) { return value; };

/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};

/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};

/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Componentizer {
    constructor() {
        this.components = {};
    }
    // createRecorder(actions, view = ()=>{}) {
    //     let path = window.location.pathname;
    //     let model = {
    //         pageLoadTimestamp: Date.now(),
    //         steps: [],
    //         components: {},
    //         recording: true,
    //         sessionName: path.substr(1, path.indexOf('.')-1).split('/').join('_')
    //     };
    //     this.recorder = new Componentizer.Component("recorder", actions, view, model);
    // }

    create(componentName, actions, view = ()=>{}, model = {}) {
        this.components[componentName] = new Componentizer.Component(componentName, actions, view, model);
    }
}

Componentizer.Component = class {
    constructor (componentName, actions, view, model) {
        if (componentName == null || componentName === "") {
            throw new Error("Your component needs a name");
        }

        if (actions == null) {
            const example = "// It must be a function that takes a model and returns an object of functions, e.g.\r\n\r\nYourComponent.Actions = function (model) {\r\n    return {\r\n        sayHello: () { console.log('Hi.'); },\r\n        greet: (name) { console.log('Hello, ' + name); }\r\n    }\r\n}";
            throw new Error(`${componentName} needs some actions! Here's an example of an Actions function:\r\n\r\n${example}\r\n\r\n`);
        }

        this.componentName = componentName;

        let _view = view && view();
        let viewInit = _view && _view.init ? _view.init : () => {};
        let render = _view && _view.render ? _view.render : () =>{};

        Object.assign(this, this.componentize(actions(model), render, model));
        viewInit(this, model);

        // if (componentizer.recorder && componentName !== "recorder") {
        //     componentizer.recorder.storeComponent(this, model);
        // }
    }

    componentize(actions, render, model) {
        render(model);
        let component = {};
        Object.keys(actions).map((action) => {
            component[action] = (...args) => {

                let returnValue = actions[action].apply(actions, args);

                // if (componentizer.recorder && componentName !== "recorder" && componentizer.recorder.get("recording")) {
                //     componentizer.recorder.recordStep(componentName, model, action, args);
                // }

                if (returnValue && returnValue.then) {
                    this.handlePromise(returnValue, render);
                }
                render(model);
            }
        }, this);
        component.get = (prop) => model[prop];
        return component;
    }

    handlePromise(promise, render) {
        promise
            .then((updatedModel)=> {
                if (updatedModel == null) {
                    throw new Error("No model received: aborting render");
                }
                render(updatedModel);
            })
            .catch((err) => {
                if (typeof err === "string") {
                    console.error(err);
                } else {
                    console.error(`Error unhandled by component. Add a catch handler to your AJAX method.`);
                }
            });
    }
};

const comp = new Componentizer();
Object.freeze(comp);

/* harmony default export */ exports["default"] = comp;

/***/ }
/******/ ]);<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on views, and components
angular.module('doc', [
  'ngRoute',
  'ngMaterial',
  'ngAnimate',
  'ngResource',
  'ngWebSocket',
  'doc.client',
  'doc.player',
  'doc.version',
]).
config(['$routeProvider', "$sceDelegateProvider", function($routeProvider, $sceDelegateProvider) {
  $routeProvider.otherwise({redirectTo: '/'});

  $sceDelegateProvider.resourceUrlWhitelist([
    "self",
    "http://www.youtube.com/**",
    "https://www.youtube.com/**"
    ])
}]).
factory("ngSocket", function($websocket){
    client.init($websocket, "127.0.0.1", "8081");
    return {};
}).
config(function($mdThemingProvider) {

    var theme = localStorage.getItem("theme_color");
    if(theme === null || theme === undefined){
        theme = "yellow";
    }

    var darkTheme = localStorage.getItem("darkTheme");
    if(darkTheme === null || darkTheme === undefined){
        darkTheme = true;
    }
    if(darkTheme !== null && darkTheme !== undefined){
        darkTheme = ( darkTheme == 'true' );
    }

    if(darkTheme){
        $mdThemingProvider.theme('default')
            .primaryPalette(theme)
            .accentPalette('orange')
            .dark();
    }
    else {
        $mdThemingProvider.theme('default')
            .primaryPalette(theme)
            .accentPalette('orange')
    }

    $mdThemingProvider.alwaysWatchTheme(true);
}).
run(["ngSocket", function(ws){

}]);
<commit_msg>fix url<commit_after>'use strict';

// Declare app level module which depends on views, and components
angular.module('doc', [
  'ngRoute',
  'ngMaterial',
  'ngAnimate',
  'ngResource',
  'ngWebSocket',
  'doc.client',
  'doc.player',
  'doc.version',
]).
config(['$routeProvider', "$sceDelegateProvider", function($routeProvider, $sceDelegateProvider) {
  $routeProvider.otherwise({redirectTo: '/'});

  $sceDelegateProvider.resourceUrlWhitelist([
    "self",
    "http://www.youtube.com/**",
    "https://www.youtube.com/**"
    ])
}]).
factory("ngSocket", function($websocket){
    client.init($websocket, "music.ndacm.org", "8081");
    return {};
}).
config(function($mdThemingProvider) {

    var theme = localStorage.getItem("theme_color");
    if(theme === null || theme === undefined){
        theme = "yellow";
    }

    var darkTheme = localStorage.getItem("darkTheme");
    if(darkTheme === null || darkTheme === undefined){
        darkTheme = true;
    }
    if(darkTheme !== null && darkTheme !== undefined){
        darkTheme = ( darkTheme == 'true' );
    }

    if(darkTheme){
        $mdThemingProvider.theme('default')
            .primaryPalette(theme)
            .accentPalette('orange')
            .dark();
    }
    else {
        $mdThemingProvider.theme('default')
            .primaryPalette(theme)
            .accentPalette('orange')
    }

    $mdThemingProvider.alwaysWatchTheme(true);
}).
run(["ngSocket", function(ws){

}]);
<|endoftext|>


<commit_before>import { matrices } from '../arithmetic/types';
const ops = matrices;

const plus = (v, w) => ops.plus(v, w);

const newPoint = (simplex, factor, fn) => {
  const dim = simplex.length - 1;
  const positions = simplex.map(vertex => vertex.pos);
  const c = ops.div(positions.slice(0, dim).reduce(plus), dim);
  const p = ops.plus(c, ops.times(factor, ops.minus(positions[dim], c)));

  return { pos: p, val: fn(p) }
};

const insert = (simplex, point) => {
  const dim = simplex.length - 1;
  let k = dim;
  while (k > 0 && point.val < simplex[k - 1].val)
    --k;
  return [].concat(simplex.slice(0, k), [point], simplex.slice(k, dim));
};

const makeSimplex = (positions, fn) => positions
  .map(p => ({ pos: p, val: fn(p) }))
  .sort((a, b) => ops.cmp(a.val, b.val));

const shrink = (simplex, fn) => makeSimplex(
  simplex.map(vertex => ops.div(ops.plus(simplex[0].pos, vertex.pos), 2.0)), fn
);

const step = (simplex, fn) => {
  const dim = simplex.length - 1;

  const pr = newPoint(simplex, -1.0, fn);

  if (pr.val < simplex[0].val) {
    const pe = newPoint(simplex, -2.0, fn);
    return insert(simplex, pe.val < pr.val ? pe : pr);
  }
  else if (pr.val < simplex[dim - 1].val)
    return insert(simplex, pr);
  else {
    const pc = newPoint(simplex, 0.5, fn);
    if (pc.val >= simplex[dim].val)
      return shrink(simplex, fn);
    else
      return insert(simplex, pc);
  }
};

const optimize = (fn, dim, start, maxSteps, tolerance) => {
  let s = makeSimplex(
    [start].concat(ops.identityMatrix(dim).map(e => ops.plus(e, start))), fn
  );
  let i = 0;

  while (i < maxSteps) {
    const vlo = s[0].val;
    const vhi = s[dim].val;
    if (2 * Math.abs(vhi - vlo) <= tolerance * (Math.abs(vlo) + Math.abs(vhi)))
      break;

    s = step(s, fn);
    ++i;
  }

  return { position: s[0].pos, value: s[0].val, steps: i };
};

if (require.main == module) {
  console.log(optimize(
    ([x, y]) => 1 + Math.pow(x - 0.4, 2) * Math.pow(y - 0.4, 2),
    2,
    [0, 0],
    1000,
    1e-12));
}
<commit_msg>improving halting condition; use more interesting example functions<commit_after>import { matrices } from '../arithmetic/types';
const ops = matrices;

const plus = (v, w) => ops.plus(v, w);

const newPoint = (simplex, factor, fn) => {
  const dim = simplex.length - 1;
  const positions = simplex.map(vertex => vertex.pos);
  const c = ops.div(positions.slice(0, dim).reduce(plus), dim);
  const p = ops.plus(c, ops.times(factor, ops.minus(positions[dim], c)));

  return { pos: p, val: fn(p) }
};

const insert = (simplex, point) => {
  const dim = simplex.length - 1;
  let k = dim;
  while (k > 0 && point.val < simplex[k - 1].val)
    --k;
  return [].concat(simplex.slice(0, k), [point], simplex.slice(k, dim));
};

const makeSimplex = (positions, fn) => positions
  .map(p => ({ pos: p, val: fn(p) }))
  .sort((a, b) => ops.cmp(a.val, b.val));

const shrink = (simplex, fn) => makeSimplex(
  simplex.map(vertex => ops.div(ops.plus(simplex[0].pos, vertex.pos), 2.0)), fn
);

const step = (simplex, fn) => {
  const dim = simplex.length - 1;

  const pr = newPoint(simplex, -1.0, fn);

  if (pr.val < simplex[0].val) {
    const pe = newPoint(simplex, -2.0, fn);
    return insert(simplex, pe.val < pr.val ? pe : pr);
  }
  else if (pr.val < simplex[dim - 1].val)
    return insert(simplex, pr);
  else {
    const pc = newPoint(simplex, 0.5, fn);
    if (pc.val >= simplex[dim].val)
      return shrink(simplex, fn);
    else
      return insert(simplex, pc);
  }
};

const optimize = (fn, dim, start, maxSteps, tolerance) => {
  let s = makeSimplex(
    [start].concat(ops.identityMatrix(dim).map(e => ops.plus(e, start))), fn
  );
  let i = 0;

  while (i < maxSteps) {
    const vlo = s[0].val;
    const vhi = s[dim].val;
    if (2 * Math.abs(vhi - vlo) <=
        tolerance * Math.max(tolerance, Math.abs(vlo) + Math.abs(vhi)))
      break;

    s = step(s, fn);
    ++i;
  }

  return { position: s[0].pos, value: s[0].val, steps: i };
};

const himmelblau = ([x, y]) =>
  Math.pow(x*x + y - 11, 2) + Math.pow(x + y*y - 7, 2);

const rosenbrock = (a, b) => ([x, y]) =>
  Math.pow(a - x, 2) + b * Math.pow(y - x*x, 2);

if (require.main == module) {
  console.log('Himmelblau:');
  console.log(optimize(himmelblau, 2, [-1, -1], 1000, 1e-12));
  console.log('Rosenbrock:');
  console.log(optimize(rosenbrock(1, 100), 2, [-1, -1], 1000, 1e-12));
}
<|endoftext|>


<commit_before>'use strict';

var angular = require('angular');

angular
  .module('mwl.calendar')
  .controller('MwlCalendarCtrl', function($scope, $timeout, $window, $attrs, $locale, moment, calendarTitle) {

    var vm = this;

    vm.events = vm.events || [];

    vm.changeView = function(view, newDay) {
      vm.view = view;
      vm.currentDay = newDay;
    };

    vm.drillDown = function(date) {

      var rawDate = moment(date).toDate();

      var nextView = {
        year: 'month',
        month: 'day',
        week: 'day'
      };

      if (vm.onDrillDownClick({calendarDate: rawDate, calendarNextView: nextView[vm.view]}) !== false) {
        vm.changeView(nextView[vm.view], rawDate);
      }

    };

    var previousDate = moment(vm.currentDay);
    var previousView = vm.view;

    function refreshCalendar() {
      if (calendarTitle[vm.view] && angular.isDefined($attrs.viewTitle)) {
        vm.viewTitle = calendarTitle[vm.view](vm.currentDay);
      }

      vm.events = vm.events.map(function(event, index) {
        Object.defineProperty(event, '$id', {enumerable: false, configurable: true, value: index});
        return event;
      });

      //if on-timespan-click="calendarDay = calendarDate" is set then don't update the view as nothing needs to change
      var currentDate = moment(vm.currentDay);
      var shouldUpdate = true;
      if (
        previousDate.clone().startOf(vm.view).isSame(currentDate.clone().startOf(vm.view)) &&
        !previousDate.isSame(currentDate) &&
        vm.view === previousView
      ) {
        shouldUpdate = false;
      }
      previousDate = currentDate;
      previousView = vm.view;

      if (shouldUpdate) {
        $scope.$broadcast('calendar.refreshView');
      }
    }

    var eventsWatched = false;

    //Refresh the calendar when any of these variables change.
    $scope.$watchGroup([
      'vm.currentDay',
      'vm.view',
      function() {
        return moment.locale() + $locale.id; //Auto update the calendar when the locale changes
      }
    ], function() {
      if (!eventsWatched) {
        eventsWatched = true;
        //need to deep watch events hence why it isn't included in the watch group
        $scope.$watch('vm.events', refreshCalendar, true); //this will call refreshCalendar when the watcher starts (i.e. now)
      } else {
        refreshCalendar();
      }
    });

  })
  .directive('mwlCalendar', function() {

    return {
      template: require('./../templates/calendar.html'),
      restrict: 'EA',
      scope: {
        events: '=',
        view: '=',
        viewTitle: '=?',
        currentDay: '=',
        editEventHtml: '=',
        deleteEventHtml: '=',
        autoOpen: '=',
        onEventClick: '&',
        onEventTimesChanged: '&',
        onEditEventClick: '&',
        onDeleteEventClick: '&',
        onTimespanClick: '&',
        onDrillDownClick: '&',
        cellModifier: '&',
        dayViewStart: '@',
        dayViewEnd: '@',
        dayViewSplit: '@'
      },
      controller: 'MwlCalendarCtrl as vm',
      bindToController: true
    };

  });
<commit_msg>Log invalid events to the console. Closes #114<commit_after>'use strict';

var angular = require('angular');

angular
  .module('mwl.calendar')
  .controller('MwlCalendarCtrl', function($scope, $log, $timeout, $window, $attrs, $locale, moment, calendarTitle) {

    var vm = this;

    vm.events = vm.events || [];

    vm.changeView = function(view, newDay) {
      vm.view = view;
      vm.currentDay = newDay;
    };

    vm.drillDown = function(date) {

      var rawDate = moment(date).toDate();

      var nextView = {
        year: 'month',
        month: 'day',
        week: 'day'
      };

      if (vm.onDrillDownClick({calendarDate: rawDate, calendarNextView: nextView[vm.view]}) !== false) {
        vm.changeView(nextView[vm.view], rawDate);
      }

    };

    var previousDate = moment(vm.currentDay);
    var previousView = vm.view;

    function eventIsValid(event) {
      if (!event.startsAt) {
        $log.warn('Bootstrap calendar: ', 'Event is missing the startsAt field', event);
      }

      if (!angular.isDate(event.startsAt)) {
        $log.warn('Bootstrap calendar: ', 'Event startsAt should be a javascript date object', event);
      }

      if (angular.isDefined(event.endsAt)) {
        if (!angular.isDate(event.endsAt)) {
          $log.warn('Bootstrap calendar: ', 'Event endsAt should be a javascript date object', event);
        }
        if (moment(event.startsAt).isAfter(moment(event.endsAt))) {
          $log.warn('Bootstrap calendar: ', 'Event cannot start after it finishes', event);
        }
      }

      return true;
    }

    function refreshCalendar() {
      if (calendarTitle[vm.view] && angular.isDefined($attrs.viewTitle)) {
        vm.viewTitle = calendarTitle[vm.view](vm.currentDay);
      }

      vm.events = vm.events.filter(eventIsValid).map(function(event, index) {
        Object.defineProperty(event, '$id', {enumerable: false, configurable: true, value: index});
        return event;
      });

      //if on-timespan-click="calendarDay = calendarDate" is set then don't update the view as nothing needs to change
      var currentDate = moment(vm.currentDay);
      var shouldUpdate = true;
      if (
        previousDate.clone().startOf(vm.view).isSame(currentDate.clone().startOf(vm.view)) &&
        !previousDate.isSame(currentDate) &&
        vm.view === previousView
      ) {
        shouldUpdate = false;
      }
      previousDate = currentDate;
      previousView = vm.view;

      if (shouldUpdate) {
        $scope.$broadcast('calendar.refreshView');
      }
    }

    var eventsWatched = false;

    //Refresh the calendar when any of these variables change.
    $scope.$watchGroup([
      'vm.currentDay',
      'vm.view',
      function() {
        return moment.locale() + $locale.id; //Auto update the calendar when the locale changes
      }
    ], function() {
      if (!eventsWatched) {
        eventsWatched = true;
        //need to deep watch events hence why it isn't included in the watch group
        $scope.$watch('vm.events', refreshCalendar, true); //this will call refreshCalendar when the watcher starts (i.e. now)
      } else {
        refreshCalendar();
      }
    });

  })
  .directive('mwlCalendar', function() {

    return {
      template: require('./../templates/calendar.html'),
      restrict: 'EA',
      scope: {
        events: '=',
        view: '=',
        viewTitle: '=?',
        currentDay: '=',
        editEventHtml: '=',
        deleteEventHtml: '=',
        autoOpen: '=',
        onEventClick: '&',
        onEventTimesChanged: '&',
        onEditEventClick: '&',
        onDeleteEventClick: '&',
        onTimespanClick: '&',
        onDrillDownClick: '&',
        cellModifier: '&',
        dayViewStart: '@',
        dayViewEnd: '@',
        dayViewSplit: '@'
      },
      controller: 'MwlCalendarCtrl as vm',
      bindToController: true
    };

  });
<|endoftext|>


<commit_before>/*global describe:true, it:true */
var request = require('supertest');
var should = require('should');
var expect = require('chai').expect;
var app = require('../index');

var _ = require('lodash');

describe('Auth', function () {

  it('should sign up the user', function () {

  });

  it('should authenticate the user', function () {

  });

  it('should logout the user', function () {

  });

});

describe('API', function () {

  //this depends on database insertions from db.tests
  describe('Project', function () {

    it('should get all of the user\'s projects on GET /project', function (done) {
      request(app)
        .get('/api/project')
        .expect(200)
        .end(function (err, res) {
          // console.log('below is body');
          // console.log(res.body);
          var projects = res.body;
          // console.log('projects', projects);
          projects.should.be.instanceof(Array);
          projects[0].should.have.property('id');
          projects[0].should.have.property('project_name');
          projects[0].should.have.property('created_at');
          projects[0].should.have.property('updated_at');
          projects[0].should.have.property('user');
          done();
        });
    });

    //SHOULD THIS BE AN OBJECT OR IS THERE A SITUATION WHERE THERE COULD BE MORE THAN ONE????
    it('should get a specific project on GET /project/:id', function (done) {
      request(app)
        .get('/api/project/2')
        .expect(200)
        .end(function (err, res) {
          var project = res.body;
          console.log('project', project);
          project.should.be.instanceof(Object);
          project.should.have.property('id');
          project.should.have.property('project_name');
          project.should.have.property('created_at');
          project.should.have.property('updated_at');
          project.should.have.property('user');
          project.user.should.be.instanceof(Array);
          done();
        });
    });

    it('should create a new project on POST /project', function () {

    });

  });

  describe('User', function () {

    it('should get all of the users and their projects on GET /user', function (done) {
      request(app)
        .get('/api/user')
        .expect(200)
        .end(function (err, res) {
          // console.log('below is body');
          // console.log(res.body);
          var users = res.body;
          console.log('users', users);
          users.should.be.instanceof(Array);
          users[0].should.have.property('id');
          users[0].should.have.property('username');
          users[0].should.have.property('githubId');
          users[0].should.have.property('githubName');
          users[0].should.have.property('githubEmail');
          users[0].should.have.property('githubLocation');
          users[0].should.have.property('githubAccessToken');
          users[0].should.have.property('githubAvatarUrl');
          users[0].should.have.property('created_at');
          users[0].should.have.property('updated_at');
          users[0].should.have.property('project');
          done();
        });
    });

    // CHANGE THIS TO GITHUB HANDLE INSTEAD OF ID!! CHANGE IT IN PROJECT CONTROLLER AND ROUTERS TOO!!!!!
    it('should get a specific user on GET /user/:id', function (done) {
      request(app)
        .get('/api/user/2')
        .expect(200)
        .end(function (err, res) {
          var user = res.body;
          console.log('user', user);
          user.should.be.instanceof(Object);
          user.should.have.property('id');
          user.should.have.property('username');
          user.should.have.property('githubId');
          user.should.have.property('githubName');
          user.should.have.property('githubEmail');
          user.should.have.property('githubLocation');
          user.should.have.property('githubAccessToken');
          user.should.have.property('githubAvatarUrl');
          user.should.have.property('created_at');
          user.should.have.property('updated_at');
          user.should.have.property('project');
          user.project.should.be.instanceof(Array);
          done();
        });
    });

    it('should get all user info on GET /user/:github_handle', function () {

    });

  });

});<commit_msg>add server logic 9<commit_after>/*global describe:true, it:true */
var request = require('supertest');
var should = require('should');
var expect = require('chai').expect;
var app = require('../index');

var _ = require('lodash');

describe('Auth', function () {

  it('should sign up the user', function () {

  });

  it('should authenticate the user', function () {

  });

  it('should logout the user', function () {

  });

});

describe('API', function () {

  //this depends on database insertions from db.tests
  describe('Project', function () {

    it('should get all of the user\'s projects on GET /project', function (done) {
      request(app)
        .get('/api/project')
        .expect(200)
        .end(function (err, res) {
          // console.log('below is body');
          // console.log(res.body);
          var projects = res.body;
          // console.log('projects', projects);
          projects.should.be.instanceof(Array);
          projects[0].should.have.property('id');
          projects[0].should.have.property('project_name');
          projects[0].should.have.property('created_at');
          projects[0].should.have.property('updated_at');
          projects[0].should.have.property('user');
          done();
        });
    });

    //SHOULD THIS BE AN OBJECT OR IS THERE A SITUATION WHERE THERE COULD BE MORE THAN ONE????
    it('should get a specific project on GET /project/:id', function (done) {
      request(app)
        .get('/api/project/2')
        .expect(200)
        .end(function (err, res) {
          var project = res.body;
          console.log('project', project);
          project.should.be.instanceof(Object);
          project.should.have.property('id');
          project.should.have.property('project_name');
          project.should.have.property('created_at');
          project.should.have.property('updated_at');
          project.should.have.property('user');
          project.user.should.be.instanceof(Array);
          done();
        });
    });

    it('should create a new project on POST /project', function () {

    });

  });

  describe('User', function () {

    it('should get all of the users and their projects on GET /user', function (done) {
      request(app)
        .get('/api/user')
        .expect(200)
        .end(function (err, res) {
          // console.log('below is body');
          // console.log(res.body);
          var users = res.body;
          console.log('users', users);
          users.should.be.instanceof(Array);
          users[0].should.have.property('id');
          users[0].should.have.property('username');
          users[0].should.have.property('githubId');
          users[0].should.have.property('githubName');
          users[0].should.have.property('githubEmail');
          users[0].should.have.property('githubLocation');
          users[0].should.have.property('githubAccessToken');
          users[0].should.have.property('githubAvatarUrl');
          users[0].should.have.property('created_at');
          users[0].should.have.property('updated_at');
          users[0].should.have.property('project');
          done();
        });
    });

    // CHANGE THIS TO GITHUB HANDLE INSTEAD OF ID!! CHANGE IT IN PROJECT CONTROLLER AND ROUTERS TOO!!!!!
    // CHANGE THE POST REQUESTS TO ADD ALL THE GITHUB STUFF TOO!!!!!!
    it('should get a specific user on GET /user/:id', function (done) {
      request(app)
        .get('/api/user/2')
        .expect(200)
        .end(function (err, res) {
          var user = res.body;
          console.log('user', user);
          user.should.be.instanceof(Object);
          user.should.have.property('id');
          user.should.have.property('username');
          user.should.have.property('githubId');
          user.should.have.property('githubName');
          user.should.have.property('githubEmail');
          user.should.have.property('githubLocation');
          user.should.have.property('githubAccessToken');
          user.should.have.property('githubAvatarUrl');
          user.should.have.property('created_at');
          user.should.have.property('updated_at');
          user.should.have.property('project');
          user.project.should.be.instanceof(Array);
          done();
        });
    });

    it('should get all user info on GET /user/:github_handle', function () {

    });

  });

});<|endoftext|>


<commit_before>import React, { PropTypes as pt } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Table, Thead, Th, Tr, Td } from 'reactable';
import classNames from 'classnames';
import moment from 'moment';
import { makeApiRequest, recipesReceived, setSelectedRecipe } from '../actions/ControlActions.js';

const BooleanIcon = props => {
  if (props.value) {
    return  ;
  }
  return  ;
};
BooleanIcon.propTypes = {
  value: pt.bool.isRequired,
};

function FilterBar({ searchText, selectedFilter, updateSearch, updateFilter }) {
  return (

          <input type="text" placeholder="Search" value={searchText} onChange={updateSearch} />

Filter By:

        <SwitchFilter
          options={['All', 'Enabled', 'Disabled']}
          selectedFilter={selectedFilter}
          updateFilter={updateFilter}
        />

  );
}
FilterBar.propTypes = {
  searchText: pt.string.isRequired,
  selectedFilter: pt.any.isRequired,
  updateSearch: pt.func.isRequired,
  updateFilter: pt.func.isRequired,
};

function SwitchFilter({ options, selectedFilter, updateFilter }) {
  return (

      <div className={`switch-selection position-${options.indexOf(selectedFilter)}`}>

      {options.map(option =>
         updateFilter(option)}
        >{option}

      )}

  );
}
SwitchFilter.propTypes = {
  options: pt.object.isRequired,
  selectedFilter: pt.any.isRequired,
  updateFilter: pt.func.isRequired,
};

class DisconnectedRecipeList extends React.Component {

  /**
   * Given a recipe object, determines what type of recipe it is (based on its `action`),
   * and then compiles a hash of 'displayed metadata props' and their values. This hash
   * is saved on the recipe as `metaData`.
   *
   * Beyond that, a string of metaData values is created, and attached to the
   * recipe as the `searchData` property. This is used by the `Table` component
   * in to search/filter over the metaData.
   *
   * @param  {Object} Original recipe received/passed into reducer
   * @return {Object} Original recipe, but with `metaData` and `searchData` properties added
   */
  static applyUniqueRecipeID(recipe) {
    const newRecipe = { ...recipe };

    switch (recipe.action) {
      case 'show-heartbeat':
        newRecipe.metaData = {
          'Survey ID': recipe.arguments.surveyId,
        };
        break;
      case 'console-log':
        newRecipe.metaData = {
          Message: recipe.arguments.message,
        };
        break;
      default:
        newRecipe.metaData = {};
        break;
    }

    // build a string of metadata values,
    // which is used for table filtering/searching later
    newRecipe.searchData = Object.keys(newRecipe.metaData)
      .map(metaProp => newRecipe.metaData[metaProp])
      .join(' ');

    return newRecipe;
  }

  constructor(props) {
    super(props);
    this.state = {
      searchText: '',
      filteredRecipes: null,
      selectedFilter: 'All',
    };

    this.updateFilter = ::this.updateFilter;
    this.updateSearch = ::this.updateSearch;
  }

  componentWillMount() {
    const { dispatch, isFetching, recipeListNeedsFetch } = this.props;
    dispatch(setSelectedRecipe(null));

    if (recipeListNeedsFetch && !isFetching) {
      dispatch(makeApiRequest('fetchAllRecipes', {}))
      .then(recipes => dispatch(recipesReceived(recipes)));
    }
  }

  title = 'Recipes';

  viewRecipe(recipe) {
    const { dispatch } = this.props;
    dispatch(setSelectedRecipe(recipe.id));
    dispatch(push(`/control/recipe/${recipe.id}/`));
  }

  updateSearch(event) {
    this.setState({
      searchText: event.target.value,
    });
  }

  updateFilter(filterStatus) {
    const { recipes } = this.props;

    if (filterStatus === 'All') {
      this.setState({
        filteredRecipes: null,
        selectedFilter: filterStatus,
      });
    } else {
      const enabledState = filterStatus === 'Enabled';
      this.setState({
        filteredRecipes: recipes.filter(recipe => recipe.enabled === enabledState),
        selectedFilter: filterStatus,
      });
    }
  }

  render() {
    const { recipes } = this.props;
    let filteredRecipes = this.state.filteredRecipes || recipes;
    filteredRecipes = filteredRecipes.map(DisconnectedRecipeList.applyUniqueRecipeID);

    return (

        <FilterBar
          {...this.state}
          updateFilter={this.updateFilter}
          updateSearch={this.updateSearch}
        />

              Name
              Action Name
              Enabled
              Last Updated
              Metadata

            {filteredRecipes.map(recipe =>

 { this.viewRecipe(recipe); }}>
                {recipe.name}
                {recipe.action}

                  <BooleanIcon value={recipe.enabled} />

                  {moment(recipe.last_updated).fromNow()}

                    {
                      Object
                        .keys(recipe.metaData)
                        .map(metaProp => (

                            {metaProp}: {recipe.metaData[metaProp]}

                        ))
                    }

              )
            }

    );
  }
}

DisconnectedRecipeList.propTypes = {
  dispatch: pt.func.isRequired,
  isFetching: pt.bool.isRequired,
  recipeListNeedsFetch: pt.bool.isRequired,
  recipe: pt.object.isRequired,
  recipes: pt.array.isRequired,
};

const mapStateToProps = (state, ownProps) => ({
  recipes: state.controlApp.recipes || [],
  dispatch: ownProps.dispatch,
  recipeListNeedsFetch: state.controlApp.recipeListNeedsFetch,
  isFetching: state.controlApp.isFetching,
});

export default connect(
  mapStateToProps
)(DisconnectedRecipeList);
<commit_msg>Clarify comments on applyUniqueRecipeID<commit_after>import React, { PropTypes as pt } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Table, Thead, Th, Tr, Td } from 'reactable';
import classNames from 'classnames';
import moment from 'moment';
import { makeApiRequest, recipesReceived, setSelectedRecipe } from '../actions/ControlActions.js';

const BooleanIcon = props => {
  if (props.value) {
    return  ;
  }
  return  ;
};
BooleanIcon.propTypes = {
  value: pt.bool.isRequired,
};

function FilterBar({ searchText, selectedFilter, updateSearch, updateFilter }) {
  return (

          <input type="text" placeholder="Search" value={searchText} onChange={updateSearch} />

Filter By:

        <SwitchFilter
          options={['All', 'Enabled', 'Disabled']}
          selectedFilter={selectedFilter}
          updateFilter={updateFilter}
        />

  );
}
FilterBar.propTypes = {
  searchText: pt.string.isRequired,
  selectedFilter: pt.any.isRequired,
  updateSearch: pt.func.isRequired,
  updateFilter: pt.func.isRequired,
};

function SwitchFilter({ options, selectedFilter, updateFilter }) {
  return (

      <div className={`switch-selection position-${options.indexOf(selectedFilter)}`}>

      {options.map(option =>
         updateFilter(option)}
        >{option}

      )}

  );
}
SwitchFilter.propTypes = {
  options: pt.object.isRequired,
  selectedFilter: pt.any.isRequired,
  updateFilter: pt.func.isRequired,
};

class DisconnectedRecipeList extends React.Component {
  /**
   * Given a recipe object, determines what type of recipe it is (based on its `action`),
   * and then compiles a hash of 'displayed metadata props' and their values. This hash
   * is saved on the recipe as `metaData`, and displayed in the 'Metadata'
   *
   * Beyond that, a string of metaData values is created, and attached to the
   * recipe as the `searchData` property. This is used by the `Table` component
   * to search/filter/sort the metaData.
   *
   * @param  {Object} Original recipe object
   * @return {Object} Original recipe but with `metaData` and `searchData` properties added
   */
  static applyUniqueRecipeID(recipe) {
    const newRecipe = { ...recipe };

    switch (recipe.action) {
      case 'show-heartbeat':
        newRecipe.metaData = {
          'Survey ID': recipe.arguments.surveyId,
        };
        break;
      case 'console-log':
        newRecipe.metaData = {
          Message: recipe.arguments.message,
        };
        break;
      default:
        newRecipe.metaData = {};
        break;
    }

    // build a string of metadata values,
    // which is used for table filtering/searching later
    newRecipe.searchData = Object.keys(newRecipe.metaData)
      .map(metaProp => newRecipe.metaData[metaProp])
      .join(' ');

    return newRecipe;
  }

  constructor(props) {
    super(props);
    this.state = {
      searchText: '',
      filteredRecipes: null,
      selectedFilter: 'All',
    };

    this.updateFilter = ::this.updateFilter;
    this.updateSearch = ::this.updateSearch;
  }

  componentWillMount() {
    const { dispatch, isFetching, recipeListNeedsFetch } = this.props;
    dispatch(setSelectedRecipe(null));

    if (recipeListNeedsFetch && !isFetching) {
      dispatch(makeApiRequest('fetchAllRecipes', {}))
      .then(recipes => dispatch(recipesReceived(recipes)));
    }
  }

  title = 'Recipes';

  viewRecipe(recipe) {
    const { dispatch } = this.props;
    dispatch(setSelectedRecipe(recipe.id));
    dispatch(push(`/control/recipe/${recipe.id}/`));
  }

  updateSearch(event) {
    this.setState({
      searchText: event.target.value,
    });
  }

  updateFilter(filterStatus) {
    const { recipes } = this.props;

    if (filterStatus === 'All') {
      this.setState({
        filteredRecipes: null,
        selectedFilter: filterStatus,
      });
    } else {
      const enabledState = filterStatus === 'Enabled';
      this.setState({
        filteredRecipes: recipes.filter(recipe => recipe.enabled === enabledState),
        selectedFilter: filterStatus,
      });
    }
  }

  render() {
    const { recipes } = this.props;
    let filteredRecipes = this.state.filteredRecipes || recipes;
    filteredRecipes = filteredRecipes.map(DisconnectedRecipeList.applyUniqueRecipeID);

    return (

        <FilterBar
          {...this.state}
          updateFilter={this.updateFilter}
          updateSearch={this.updateSearch}
        />

              Name
              Action Name
              Enabled
              Last Updated
              Metadata

            {filteredRecipes.map(recipe =>

 { this.viewRecipe(recipe); }}>
                {recipe.name}
                {recipe.action}

                  <BooleanIcon value={recipe.enabled} />

                  {moment(recipe.last_updated).fromNow()}

                    {
                      Object
                        .keys(recipe.metaData)
                        .map(metaProp => (

                            {metaProp}: {recipe.metaData[metaProp]}

                        ))
                    }

              )
            }

    );
  }
}

DisconnectedRecipeList.propTypes = {
  dispatch: pt.func.isRequired,
  isFetching: pt.bool.isRequired,
  recipeListNeedsFetch: pt.bool.isRequired,
  recipe: pt.object.isRequired,
  recipes: pt.array.isRequired,
};

const mapStateToProps = (state, ownProps) => ({
  recipes: state.controlApp.recipes || [],
  dispatch: ownProps.dispatch,
  recipeListNeedsFetch: state.controlApp.recipeListNeedsFetch,
  isFetching: state.controlApp.isFetching,
});

export default connect(
  mapStateToProps
)(DisconnectedRecipeList);
<|endoftext|>


<commit_before>import React from "react/addons";
import {GoogleMaps, Marker} from "react-google-maps";

const {update} = React.addons;
/*
 * This is the modify version of:
 * https://developers.google.com/maps/documentation/javascript/examples/event-arguments
 */
class GettingStarted extends React.Component {

  constructor (...args) {
    super(...args);
    this.state = {
      markers: [{
        position: {
          lat: 25.0112183,
          lng: 121.52067570000001,
        },
        key: "Taiwan",
      }],
    };
  }

  /*
   * This is called when you click on the map.
   * Go and try click now.
   */
  _handle_map_click (event) {
    var {markers} = this.state;
    markers = update(markers, {
      $push: [
        {
          position: event.latLng,
          key: Date.now(),// Add a key property for: http://fb.me/react-warning-keys
        },
      ],
    });
    this.setState({ markers });

    if (3 === markers.length) {
      this.props.toast(
        "Right click on the marker to remove it",
        "Also check the code!"
      );
    }
    this.refs.map.panTo(event.latLng);
  }

  _handle_marker_rightclick (index, event) {
    /*
     * All you modify is data, and the view is driven by data.
     * This is so called data-driven-development. (And yes, it's now in
     * web front end and even with google maps API.)
     */
    var {markers} = this.state;
    markers = update(markers, {
      $splice: [
        [index, 1]
      ],
    });
    this.setState({ markers });
  }

  render () {
    const {props, state} = this,
          {googleMapsApi, ...otherProps} = props;

    return (
      <GoogleMaps containerProps={{
          ...otherProps,
          style: {
            height: "100%",
          },
        }}
        ref="map"
        googleMapsApi={
          "undefined" !== typeof google ? google.maps : null
        }
        zoom={3}
        center={{lat: -25.363882, lng: 131.044922}}
        onClick={this._handle_map_click.bind(this)}>
        {state.markers.map(toMarker, this)}
      </GoogleMaps>
    );

    function toMarker (marker, index) {
      return (
        <Marker
          position={marker.position}
          key={marker.key}
          onRightclick={this._handle_marker_rightclick.bind(this, index)} />
      );
    }
  }
}

export default GettingStarted;
<commit_msg>chore(examples): edit the gettingStarted example to demonstrate that animations on marker now works as expected<commit_after>import React from "react/addons";
import {GoogleMaps, Marker} from "react-google-maps";

const {update} = React.addons;
/*
 * This is the modify version of:
 * https://developers.google.com/maps/documentation/javascript/examples/event-arguments
 */
class GettingStarted extends React.Component {

  constructor (...args) {
    super(...args);
    this.state = {
      markers: [{
        position: {
          lat: 25.0112183,
          lng: 121.52067570000001,
        },
        key: "Taiwan",
        animation: 2
      }],
    };
  }

  /*
   * This is called when you click on the map.
   * Go and try click now.
   */
  _handle_map_click (event) {
    var {markers} = this.state;
    markers = update(markers, {
      $push: [
        {
          position: event.latLng,
          animation: 2,
          key: Date.now(),// Add a key property for: http://fb.me/react-warning-keys
        },
      ],
    });
    this.setState({ markers });

    if (3 === markers.length) {
      this.props.toast(
        "Right click on the marker to remove it",
        "Also check the code!"
      );
    }
    this.refs.map.panTo(event.latLng);
  }

  _handle_marker_rightclick (index, event) {
    /*
     * All you modify is data, and the view is driven by data.
     * This is so called data-driven-development. (And yes, it's now in
     * web front end and even with google maps API.)
     */
    var {markers} = this.state;
    markers = update(markers, {
      $splice: [
        [index, 1]
      ],
    });
    this.setState({ markers });
  }

  render () {
    const {props, state} = this,
          {googleMapsApi, ...otherProps} = props;

    return (
      <GoogleMaps containerProps={{
          ...otherProps,
          style: {
            height: "100%",
          },
        }}
        ref="map"
        googleMapsApi={
          "undefined" !== typeof google ? google.maps : null
        }
        zoom={3}
        center={{lat: -25.363882, lng: 131.044922}}
        onClick={this._handle_map_click.bind(this)}>
        {state.markers.map(toMarker, this)}
      </GoogleMaps>
    );

    function toMarker (marker, index) {
      return (
        <Marker
          position={marker.position}
          key={marker.key}
          animation={marker.animation}
          onRightclick={this._handle_marker_rightclick.bind(this, index)} />
      );
    }
  }
}

export default GettingStarted;
<|endoftext|>


<commit_before>App.run(function ($rootScope, $state, AuthService, AUTH_EVENTS, NAV_TABS, NESTED_VIEWS, Session) {
    function checkAuthorized(authorizedRoles) {
        if (!AuthService.isAuthorized(authorizedRoles)) {
            if (AuthService.isAuthenticated()) {
                // user is not allowed
                $rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
            } else {
                // user is not logged in
                $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
            }
            return false;
        }
        return true;
    }

    function iAmNotAuthorizedToBeHere() {
        // If I am already in an unauthorized state
        var allStates = _.extend(NESTED_VIEWS, NAV_TABS);
        var allStatesArray = Object.keys(allStates).map(function(k){return allStates[k]});
        var currentState = _.find( allStatesArray, function(s) { return s.stateName == $state.current.name; });
        return !checkAuthorized(currentState.data.authorizedRoles);
    }

    $rootScope.$on(AUTH_EVENTS.logoutSuccess, function() {
        if (iAmNotAuthorizedToBeHere()) {
            $state.go(NAV_TABS.group.stateName, {});
        }
    });

    $rootScope.$on(AUTH_EVENTS.authServiceInitialized, function() {

        $rootScope.$on('$stateChangeStart', function (event, next) {
            var authorizedRoles = next.data.authorizedRoles;
            if (!checkAuthorized(authorizedRoles)) {
                event.preventDefault();
            }
        });
        if (iAmNotAuthorizedToBeHere()) {
            $state.go(NAV_TABS.group.stateName, {});
        }
    });
});

App.config(function ($httpProvider) {
  $httpProvider.interceptors.push([
    '$injector',
    function ($injector) {
      return $injector.get('AuthInterceptor');
    }
  ]);
});

App.factory('AuthInterceptor', function ($rootScope, $q,
                                         AUTH_EVENTS) {
  return {
    responseError: function (response) {
      $rootScope.$broadcast({
        401: AUTH_EVENTS.notAuthenticated,
        403: AUTH_EVENTS.notAuthorized,
        419: AUTH_EVENTS.sessionTimeout,
        440: AUTH_EVENTS.sessionTimeout
      }[response.status], response);
      return $q.reject(response);
    }
  };
});

App.service('YammerSession', function () {
    this.create = function (token, userId) {
        this.token = token;
        this.userId = userId;
    };
    this.destroy = function () {
        this.token = null;
        this.userId = null;
    };
    return this;
});

App.service('Session', function (USER_ROLES) {
    this.create = function (token, userId, userRole, groupsAdmin) {
        this.token = token;
        this.userId = userId;
        this.userRole = userRole;
        this.groupsAdmin = groupsAdmin;
    };
    this.destroy = function () {
        this.token = null;
        this.userId = null;
        this.userRole = USER_ROLES.guest;
        this.groupsAdmin = null;
    };
    this.destroy();
    return this;
});

App.factory('SessionStorage', ['$window', function($window) {
    var SessionStorage = {};

    SessionStorage.save = function(key, value) {
        $window.localStorage.setItem(key, JSON.stringify(value));
    }
    SessionStorage.load = function(key) {
        var value = $window.localStorage.getItem(key);
        if (value) {
            return JSON.parse(value);
        }
        return undefined;
    }
    return SessionStorage;

}]);

App.factory('AuthService', function ($rootScope, $http, $q, $timeout, Session, YammerSession, SessionStorage, yammer,
                                     AuthorizationResource, USER_ROLES, AUTH_EVENTS) {
    var authService = {};

    function createAuthorizationHeader(yammerSession) {
        $http.defaults.headers.common.Authorization = 'ST-AUTH access-token = \"' +
                                                      yammerSession.token +
                                                      '\",' +
                                                      " yammer-id = \"" +
                                                      yammerSession.userId  +
                                                      "\"";
    }

    function destroyAuthorizationHeader() {
        $http.defaults.headers.common.Authorization = undefined;
    }

    function getStresstimeUserStatus() {
        return AuthorizationResource.get().$promise;

    }

    function updateYammerSession(yammerResponse) {
        if (yammerResponse.authResponse) {
            YammerSession.create(yammerResponse.access_token.token, yammerResponse.access_token.user_id);
        } else {
            YammerSession.destroy();
        }
    }

    function loginStresstime(yammerSession) {
        createAuthorizationHeader(yammerSession);
        return getStresstimeUserStatus().then(function(userStatus) {
            if (userStatus.role ==  USER_ROLES.guest) {
                console.error("Something is wrong with the Authorization header. Logged user can not be a guest.");
                return;
            }
            Session.create(yammerSession.token, userStatus.employeeId, userStatus.role, userStatus.groupsAdmin);
            SessionStorage.save('session', Session);
            return userStatus;
        });
    }

    function initializeAuthService() {
        yammer.getLoginStatus(function(response) {
            updateYammerSession(response);
            var session = SessionStorage.load('session');
            if(YammerSession.token && session) {
                if (session.userRole == USER_ROLES.guest) {
                    Session.create(session.token, session.userId, session.userRole, session.groupsAdmin);
                    $rootScope.$broadcast(AUTH_EVENTS.authServiceInitialized);
                }
                else {
                    loginStresstime(YammerSession).then(function(userStatus) {
                        $rootScope.$broadcast(AUTH_EVENTS.authServiceInitialized);
                    });
                }
            } else {
                $rootScope.$broadcast(AUTH_EVENTS.authServiceInitialized);
            }

        });
    }

    authService.login = function () {
        var deferredYammerResponse = $q.defer();
        if (!YammerSession.token) {
            yammer.login(function (response) {
                updateYammerSession(response);
                deferredYammerResponse.resolve(YammerSession);
            });
        }
        else {
            deferredYammerResponse.resolve(YammerSession);
        }
        var deferred = $q.defer();
        deferredYammerResponse.promise.then(function(yammerSession) {
            loginStresstime(yammerSession).then(function(userStatus) {
                deferred.resolve(userStatus);
            });
        });
        return deferred.promise;
    };

    authService.logout = function() {
        var deferred = $q.defer(); // this is done just to be compatible with the login function
        deferred.resolve();
        destroyAuthorizationHeader();
        Session.destroy();
        SessionStorage.save("session", Session);
        return deferred.promise;
    }

    authService.isAuthenticated = function () {
        return !!Session.userId;
    };

    authService.isAuthorized = function (authorizedRoles, groupId) {
        if (!angular.isArray(authorizedRoles)) {
            authorizedRoles = [authorizedRoles];
        }
        if (authorizedRoles.indexOf(Session.userRole) === -1) {
            return false;
        }
        if (groupId == undefined) { // no further conditions
            return true;
        }
        return Session.groupsAdmin && Session.groupsAdmin.indexOf(groupId) !== -1;
    };

    authService.belongsToGroup = function(group) {
        return group.employeeMap != undefined && group.employeeMap[Session.userId] != undefined;
    }

    authService.removeGroupAdminPrivileges = function(groupId) {
        Session.groupsAdmin.remove(groupId);
        SessionStorage.save("session", Session);
    }

    authService.removeGlobalAdminPrivileges = function() {
        if (Session.userRole == USER_ROLES.globalAdmin) {
            Session.userRole = USER_ROLES.user;
        }
        SessionStorage.save("session", Session);
    }

    initializeAuthService();
    return authService;
});<commit_msg>Save yammer session and set authorization header<commit_after>App.run(function ($rootScope, $state, AuthService, AUTH_EVENTS, NAV_TABS, NESTED_VIEWS, Session) {
    function checkAuthorized(authorizedRoles) {
        if (!AuthService.isAuthorized(authorizedRoles)) {
            if (AuthService.isAuthenticated()) {
                // user is not allowed
                $rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
            } else {
                // user is not logged in
                $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
            }
            return false;
        }
        return true;
    }

    function iAmNotAuthorizedToBeHere() {
        // If I am already in an unauthorized state
        var allStates = _.extend(NESTED_VIEWS, NAV_TABS);
        var allStatesArray = Object.keys(allStates).map(function(k){return allStates[k]});
        var currentState = _.find( allStatesArray, function(s) { return s.stateName == $state.current.name; });
        return !checkAuthorized(currentState.data.authorizedRoles);
    }

    $rootScope.$on(AUTH_EVENTS.logoutSuccess, function() {
        if (iAmNotAuthorizedToBeHere()) {
            $state.go(NAV_TABS.group.stateName, {});
        }
    });

    $rootScope.$on(AUTH_EVENTS.authServiceInitialized, function() {

        $rootScope.$on('$stateChangeStart', function (event, next) {
            var authorizedRoles = next.data.authorizedRoles;
            if (!checkAuthorized(authorizedRoles)) {
                event.preventDefault();
            }
        });
        if (iAmNotAuthorizedToBeHere()) {
            $state.go(NAV_TABS.group.stateName, {});
        }
    });
});

App.config(function ($httpProvider) {
  $httpProvider.interceptors.push([
    '$injector',
    function ($injector) {
      return $injector.get('AuthInterceptor');
    }
  ]);
});

App.factory('AuthInterceptor', function ($rootScope, $q,
                                         AUTH_EVENTS) {
  return {
    responseError: function (response) {
      $rootScope.$broadcast({
        401: AUTH_EVENTS.notAuthenticated,
        403: AUTH_EVENTS.notAuthorized,
        419: AUTH_EVENTS.sessionTimeout,
        440: AUTH_EVENTS.sessionTimeout
      }[response.status], response);
      return $q.reject(response);
    }
  };
});

App.service('YammerSession', function () {
    this.create = function (token, userId) {
        this.token = token;
        this.userId = userId;
    };
    this.destroy = function () {
        this.token = null;
        this.userId = null;
    };
    return this;
});

App.service('Session', function (USER_ROLES) {
    this.create = function (token, userId, userRole, groupsAdmin) {
        this.token = token;
        this.userId = userId;
        this.userRole = userRole;
        this.groupsAdmin = groupsAdmin;
    };
    this.destroy = function () {
        this.token = null;
        this.userId = null;
        this.userRole = USER_ROLES.guest;
        this.groupsAdmin = null;
    };
    this.destroy();
    return this;
});

App.factory('SessionStorage', ['$window', function($window) {
    var SessionStorage = {};

    SessionStorage.save = function(key, value) {
        $window.localStorage.setItem(key, JSON.stringify(value));
    }
    SessionStorage.load = function(key) {
        var value = $window.localStorage.getItem(key);
        if (value) {
            return JSON.parse(value);
        }
        return undefined;
    }
    return SessionStorage;

}]);

function createAuthorizationHeader($http, yammerSession) {
    $http.defaults.headers.common.Authorization = 'ST-AUTH access-token = \"' +
                                                  yammerSession.token +
                                                  '\",' +
                                                  " yammer-id = \"" +
                                                  yammerSession.userId  +
                                                  "\"";
}

App.factory('AuthService', function ($rootScope, $http, $q, $timeout, Session, YammerSession, SessionStorage, yammer,
                                     AuthorizationResource, USER_ROLES, AUTH_EVENTS) {
    var authService = {};

    function destroyAuthorizationHeader() {
        $http.defaults.headers.common.Authorization = undefined;
    }

    function getStresstimeUserStatus() {
        return AuthorizationResource.get().$promise;

    }

    function updateYammerSession(yammerResponse) {
        if (yammerResponse.authResponse) {
            YammerSession.create(yammerResponse.access_token.token, yammerResponse.access_token.user_id);
            SessionStorage.save("yammerSession", YammerSession);
        } else {
            YammerSession.destroy();
            SessionStorage.save("yammerSession", YammerSession);
        }
    }

    function loginStresstime(yammerSession) {
        createAuthorizationHeader($http, yammerSession);
        return getStresstimeUserStatus().then(function(userStatus) {
            if (userStatus.role ==  USER_ROLES.guest) {
                console.error("Something is wrong with the Authorization header. Logged user can not be a guest.");
                return;
            }
            Session.create(yammerSession.token, userStatus.employeeId, userStatus.role, userStatus.groupsAdmin);
            SessionStorage.save('session', Session);
            return userStatus;
        });
    }

    function initializeAuthService() {
        yammer.getLoginStatus(function(response) {
            updateYammerSession(response);
            var session = SessionStorage.load('session');
            if(YammerSession.token && session) {
                if (session.userRole == USER_ROLES.guest) {
                    Session.create(session.token, session.userId, session.userRole, session.groupsAdmin);
                    $rootScope.$broadcast(AUTH_EVENTS.authServiceInitialized);
                }
                else {
                    loginStresstime(YammerSession).then(function(userStatus) {
                        $rootScope.$broadcast(AUTH_EVENTS.authServiceInitialized);
                    });
                }
            } else {
                $rootScope.$broadcast(AUTH_EVENTS.authServiceInitialized);
            }

        });
    }

    authService.login = function () {
        var deferredYammerResponse = $q.defer();
        if (!YammerSession.token) {
            yammer.login(function (response) {
                updateYammerSession(response);
                deferredYammerResponse.resolve(YammerSession);
            });
        }
        else {
            deferredYammerResponse.resolve(YammerSession);
        }
        var deferred = $q.defer();
        deferredYammerResponse.promise.then(function(yammerSession) {
            loginStresstime(yammerSession).then(function(userStatus) {
                deferred.resolve(userStatus);
            });
        });
        return deferred.promise;
    };

    authService.logout = function() {
        var deferred = $q.defer(); // this is done just to be compatible with the login function
        deferred.resolve();
        destroyAuthorizationHeader();
        Session.destroy();
        SessionStorage.save("session", Session);
        return deferred.promise;
    }

    authService.isAuthenticated = function () {
        return !!Session.userId;
    };

    authService.isAuthorized = function (authorizedRoles, groupId) {
        if (!angular.isArray(authorizedRoles)) {
            authorizedRoles = [authorizedRoles];
        }
        if (authorizedRoles.indexOf(Session.userRole) === -1) {
            return false;
        }
        if (groupId == undefined) { // no further conditions
            return true;
        }
        return Session.groupsAdmin && Session.groupsAdmin.indexOf(groupId) !== -1;
    };

    authService.belongsToGroup = function(group) {
        return group.employeeMap != undefined && group.employeeMap[Session.userId] != undefined;
    }

    authService.removeGroupAdminPrivileges = function(groupId) {
        Session.groupsAdmin.remove(groupId);
        SessionStorage.save("session", Session);
    }

    authService.removeGlobalAdminPrivileges = function() {
        if (Session.userRole == USER_ROLES.globalAdmin) {
            Session.userRole = USER_ROLES.user;
        }
        SessionStorage.save("session", Session);
    }

    initializeAuthService();
    return authService;
});

App.run(["SessionStorage", "$http", function(SessionStorage, $http) {
    var yammerSession = SessionStorage.load("yammerSession");
    if(yammerSession){
        createAuthorizationHeader($http, yammerSession);
    }
}]);<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone, $, window */

window.ArangoUsers = Backbone.Collection.extend({
  model: window.Users,

  activeUser: "",
  activeUserSettings: {
    "query" : {},
    "shell" : {},
    "testing": true
  },

  url: "../api/user",

  initialize: function() {
    //check cookies / local storage
  },

  login: function (username, password) {
    this.activeUser = username;
    return true;
  },

  logout: function () {
    this.activeUser = undefined;
    this.reset();
  },

  setUserSettings: function (identifier, content) {
    this.activeUserSettings.identifier = content;
  },

  loadUserSettings: function () {
    var self = this;
    $.ajax({
      type: "GET",
      cache: false,
      url: "/_api/user/" + self.activeUser,
      contentType: "application/json",
      processData: false,
      async: false,
      success: function(data) {
        self.activeUserSettings = data.extra;
      },
      error: function(data) {
      }
    });
  },

  saveUserSettings: function () {
    var self = this;
    $.ajax({
      cache: false,
      type: "PUT",
      async: false, // sequential calls!
      url: "/_api/user/" + self.activeUser,
      data: JSON.stringify({ extra: self.activeUserSettings }),
      contentType: "application/json",
      processData: false,
      success: function(data) {
      },
      error: function(data) {
      }
    });
  }

});
<commit_msg>path fixed<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone, $, window */

window.ArangoUsers = Backbone.Collection.extend({
  model: window.Users,

  activeUser: "",
  activeUserSettings: {
    "query" : {},
    "shell" : {},
    "testing": true
  },

  url: "/_api/user",

  initialize: function() {
    //check cookies / local storage
  },

  login: function (username, password) {
    this.activeUser = username;
    return true;
  },

  logout: function () {
    this.activeUser = undefined;
    this.reset();
  },

  setUserSettings: function (identifier, content) {
    this.activeUserSettings.identifier = content;
  },

  loadUserSettings: function () {
    var self = this;
    $.ajax({
      type: "GET",
      cache: false,
      url: "/_api/user/" + self.activeUser,
      contentType: "application/json",
      processData: false,
      async: false,
      success: function(data) {
        self.activeUserSettings = data.extra;
      },
      error: function(data) {
      }
    });
  },

  saveUserSettings: function () {
    var self = this;
    $.ajax({
      cache: false,
      type: "PUT",
      async: false, // sequential calls!
      url: "/_api/user/" + self.activeUser,
      data: JSON.stringify({ extra: self.activeUserSettings }),
      contentType: "application/json",
      processData: false,
      success: function(data) {
      },
      error: function(data) {
      }
    });
  }

});
<|endoftext|>


<commit_before>import { registerOption } from 'pretty-text/pretty-text';

registerOption((siteSettings, opts) => {
  opts.features.furigana = !!siteSettings.furigana_enabled;
  opts.furiganaForms = siteSettings.furigana_plugin_forms;
  opts.furiganaFallbackBrackets = siteSettings.furigana_fallback_brackets;
  opts.furiganaStrictMode = !!siteSettings.furigana_strict_mode;
  opts.furiganaAutoBracketSets = siteSettings.furigana_plugin_auto_bracket_sets;
  opts.furiganaPatternMatching = siteSettings.furigana_pattern_matching;
});

// This function escapes special characters for use in a regex constructor.
function escapeForRegex(string) {
  return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

function emptyStringFilter(block) {
  return block !== '';
}

const kanjiRange = '\\u4e00-\\u9faf';
const kanjiBlockRegex = new RegExp(`[${kanjiRange}]+`, 'g');
const nonKanjiBlockRegex = new RegExp(`[^${kanjiRange}]+`, 'g');
const kanaWithAnnotations = '\\u3041-\\u3095\\u3099-\\u309c\\u3081-\\u30fa\\u30fc';
const furiganaSeperators = '.．。・';
const seperatorRegex = new RegExp(`[${furiganaSeperators}]`, 'g');

const singleKanjiRegex = new RegExp(`^[${kanjiRange}]$`);
function isKanji(character) {
  return character.match(singleKanjiRegex);
}

let regexList = [];
let previousFuriganaForms = '';

function updateRegexList(furiganaForms) {
  previousFuriganaForms = furiganaForms;
  const innerRegexString = '(?:[^\\u0000-\\u007F]|\\w)+';
  let formArray = furiganaForms.split('|');
  if (formArray.length === 0) {
    formArray = ['[]:^:()'];
  }
  regexList = formArray.map(form => {
    let furiganaComponents = form.split(':');
    if (furiganaComponents.length !== 3) {
      furiganaComponents = ['[]', '^', '()'];
    }
    const mainBrackets = furiganaComponents[0];
    const seperator = furiganaComponents[1];
    const furiganaBrackets = furiganaComponents[2];
    return new RegExp(
      escapeForRegex(mainBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(mainBrackets[1]) +
      escapeForRegex(seperator) +
      escapeForRegex(furiganaBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(furiganaBrackets[1]),
      'g'
    );
  });
}

let autoRegexList = [];
let previousAutoBracketSets = '';

function updateAutoRegexList(autoBracketSets) {
  previousAutoBracketSets = autoBracketSets;
  autoRegexList = autoBracketSets.split('|').map(brackets => {
    /*
      Sample built regex (hiragana only):
      (^|[^\u4e00-\u9faf])([\u4e00-\u9faf]+)([\u3041-\u3095\u3099-\u309c]*)【([^\u4e00-\u9faf]+)】
    */
    return new RegExp(
      `(^|[^${escapeForRegex(brackets)}${kanjiRange}])` +
      `([${kanjiRange}]+)` +
      `([${kanaWithAnnotations}]*)` +
      escapeForRegex(brackets[0]) +
      `((?:[^${escapeForRegex(brackets)}${kanjiRange}]|\w)+)` +
      escapeForRegex(brackets[1]),
      'g'
    );
  });
}

let replacementTemplate = '';
let replacementBrackets = '';

function updateReplacementTemplate(furiganaFallbackBrackets) {
  if (furiganaFallbackBrackets.length !== 2) {
    furiganaFallbackBrackets = '【】';
  }
  replacementBrackets = furiganaFallbackBrackets;
  replacementTemplate = `<ruby>$1<rp>${furiganaFallbackBrackets[0]}</rp><rt>$2</rt><rp>${furiganaFallbackBrackets[1]}</rp></ruby>`;
}

updateReplacementTemplate('【】');

function addFurigana(text, options) {
  if (options.furiganaForms !== previousFuriganaForms) {
    updateRegexList(options.furiganaForms);
  }
  if (options.furiganaFallbackBrackets !== replacementBrackets) {
    updateReplacementTemplate(options.furiganaFallbackBrackets);
  }
  regexList.forEach(regex => {
    text = text.replace(regex, (match, wordText, furiganaText, offset, mainText) => {
      if (match.indexOf('\\') === -1 && mainText[offset - 1] !== '\\') {
        let nonKanji = wordText.split(kanjiBlockRegex).filter(emptyStringFilter);
        if ((!options.furiganaPatternMatching) || nonKanji.length === 0) {
          return replacementTemplate.replace('$1', wordText).replace('$2', furiganaText);
        } else {
          let kanji = wordText.split(nonKanjiBlockRegex).filter(emptyStringFilter);
          let replacementText = '';
          nonKanji.forEach((currentNonKanji, index) => {
            if (furiganaText === undefined) {
              if (index < kanji.length) {
                replacementText += kanji[index];
              }

              replacementText += currentNonKanji;
              return;
            }
            let splitFurigana = furiganaText.split(new RegExp(escapeForRegex(currentNonKanji) + '(.*)')).filter(emptyStringFilter);
            replacementText += replacementTemplate.replace('$1', kanji[index]).replace('$2', splitFurigana[0]);
            replacementText += currentNonKanji;
            furiganaText = splitFurigana[1];
          });
          return replacementText;
        }
      } else {
        return match;
      }
    });
  });

  if (!options.furiganaStrictMode) {
    if (options.furiganaAutoBracketSets !== previousAutoBracketSets) {
      updateAutoRegexList(options.furiganaAutoBracketSets);
    }
    autoRegexList.forEach(regex => {
      text = text.replace(regex, (match, preWordTerminator, wordKanji, wordKanaSuffix, furiganaText, offset, mainText) => {
        if (match.indexOf('\\') === -1) {
          if (options.furiganaPatternMatching) {
            let rubies = [];

            let furigana = furiganaText;

            //put in if
            let stem = (' ' + wordKanaSuffix).slice(1);
            for (let i = furiganaText.length - 1; i >= 0; i--) {
              if (wordKanaSuffix.length === 0) {
                furigana = furiganaText.substring(0, i + 1);
                break;
              }
              if (furiganaText[i] !== wordKanaSuffix.slice(-1)) {
                furigana = furiganaText.substring(0, i + 1);
                break;
              }
              wordKanaSuffix = wordKanaSuffix.slice(0, -1);
            }

            if (furiganaSeperators.split('').reduce(
              (noSeperator, seperator) => {
                return noSeperator && (furigana.indexOf(seperator) === -1);
              },
              true
            )) {
              rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
            } else {
              let kanaParts = furigana.split(seperatorRegex);
              let kanji = wordKanji.split('');
              if (kanaParts.length !== kanji.length) {
                rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
              } else {
                for (let i = 0; i < wordKanji.length; i++) {
                  rubies.push(replacementTemplate.replace('$1', wordKanji).replace('$2', kanaParts[i]));
                }
              }
            }

            return preWordTerminator + rubies.join('') + stem;
          } else {
            return preWordTerminator + replacementTemplate.replace('$1', wordKanji).replace('$2', furiganaText) + wordKanaSuffix;
          }
        } else {
          return match;
        }
      });
    });
  }
  return text;
}

function handleEscapedSpecialBrackets(text) {
  // By default 【 and 】 cannot be escaped in markdown, this will remove backslashes from in front of them to give that effect.
  return text.replace(/\\([【】])/g, '$1');
}

export function setup(helper) {
  helper.whiteList([
    'ruby',
    'rt',
    'rp'
  ]);

  helper.addPreProcessor(text => {
    return handleEscapedSpecialBrackets(addFurigana(text, helper.getOptions()));
  });
}
<commit_msg>Fix various pattern matching issues<commit_after>import { registerOption } from 'pretty-text/pretty-text';

registerOption((siteSettings, opts) => {
  opts.features.furigana = !!siteSettings.furigana_enabled;
  opts.furiganaForms = siteSettings.furigana_plugin_forms;
  opts.furiganaFallbackBrackets = siteSettings.furigana_fallback_brackets;
  opts.furiganaStrictMode = !!siteSettings.furigana_strict_mode;
  opts.furiganaAutoBracketSets = siteSettings.furigana_plugin_auto_bracket_sets;
  opts.furiganaPatternMatching = siteSettings.furigana_pattern_matching;
});

// This function escapes special characters for use in a regex constructor.
function escapeForRegex(string) {
  return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

function emptyStringFilter(block) {
  return block !== '';
}

const kanjiRange = '\\u4e00-\\u9faf';
const kanjiBlockRegex = new RegExp(`[${kanjiRange}]+`, 'g');
const nonKanjiBlockRegex = new RegExp(`[^${kanjiRange}]+`, 'g');
const kanaWithAnnotations = '\\u3041-\\u3095\\u3099-\\u309c\\u3081-\\u30fa\\u30fc';
const furiganaSeperators = '.．。・';
const seperatorRegex = new RegExp(`[${furiganaSeperators}]`, 'g');

const singleKanjiRegex = new RegExp(`^[${kanjiRange}]$`);
function isKanji(character) {
  return character.match(singleKanjiRegex);
}

let regexList = [];
let previousFuriganaForms = '';

function updateRegexList(furiganaForms) {
  previousFuriganaForms = furiganaForms;
  const innerRegexString = '(?:[^\\u0000-\\u007F]|\\w)+';
  let formArray = furiganaForms.split('|');
  if (formArray.length === 0) {
    formArray = ['[]:^:()'];
  }
  regexList = formArray.map(form => {
    let furiganaComponents = form.split(':');
    if (furiganaComponents.length !== 3) {
      furiganaComponents = ['[]', '^', '()'];
    }
    const mainBrackets = furiganaComponents[0];
    const seperator = furiganaComponents[1];
    const furiganaBrackets = furiganaComponents[2];
    return new RegExp(
      escapeForRegex(mainBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(mainBrackets[1]) +
      escapeForRegex(seperator) +
      escapeForRegex(furiganaBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(furiganaBrackets[1]),
      'g'
    );
  });
}

let autoRegexList = [];
let previousAutoBracketSets = '';

function updateAutoRegexList(autoBracketSets) {
  previousAutoBracketSets = autoBracketSets;
  autoRegexList = autoBracketSets.split('|').map(brackets => {
    /*
      Sample built regex (hiragana only):
      (^|[^\u4e00-\u9faf])([\u4e00-\u9faf]+)([\u3041-\u3095\u3099-\u309c]*)【([^\u4e00-\u9faf]+)】
    */
    return new RegExp(
      `(^|[^${escapeForRegex(brackets)}${kanjiRange}])` +
      `([${kanjiRange}]+)` +
      `([${kanaWithAnnotations}]*)` +
      escapeForRegex(brackets[0]) +
      `((?:[^${escapeForRegex(brackets)}${kanjiRange}]|\w)+)` +
      escapeForRegex(brackets[1]),
      'g'
    );
  });
}

let replacementTemplate = '';
let replacementBrackets = '';

function updateReplacementTemplate(furiganaFallbackBrackets) {
  if (furiganaFallbackBrackets.length !== 2) {
    furiganaFallbackBrackets = '【】';
  }
  replacementBrackets = furiganaFallbackBrackets;
  replacementTemplate = `<ruby>$1<rp>${furiganaFallbackBrackets[0]}</rp><rt>$2</rt><rp>${furiganaFallbackBrackets[1]}</rp></ruby>`;
}

updateReplacementTemplate('【】');

function addFurigana(text, options) {
  if (options.furiganaForms !== previousFuriganaForms) {
    updateRegexList(options.furiganaForms);
  }
  if (options.furiganaFallbackBrackets !== replacementBrackets) {
    updateReplacementTemplate(options.furiganaFallbackBrackets);
  }
  regexList.forEach(regex => {
    text = text.replace(regex, (match, wordText, furiganaText, offset, mainText) => {
      if (match.indexOf('\\') === -1 && mainText[offset - 1] !== '\\') {
        if ((!options.furiganaPatternMatching) || wordText.search(kanjiBlockRegex) === -1 || wordText[0].search(kanjiBlockRegex) === -1) {
          return replacementTemplate.replace('$1', wordText).replace('$2', furiganaText);
        } else {
          let originalFuriganaText = (' ' + furiganaText).slice(1);
          let nonKanji = wordText.split(kanjiBlockRegex).filter(emptyStringFilter);
          let kanji = wordText.split(nonKanjiBlockRegex).filter(emptyStringFilter);
          let replacementText = '';
          let lastUsedKanjiIndex = 0;
          if (nonKanji.length === 0) {
            return replacementTemplate.replace('$1', wordText).replace('$2', furiganaText);
          }

          nonKanji.forEach((currentNonKanji, index) => {
            if (furiganaText === undefined) {
              if (index < kanji.length) {
                replacementText += kanji[index];
              }

              replacementText += currentNonKanji;
              return;
            }
            let splitFurigana = furiganaText.split(new RegExp(escapeForRegex(currentNonKanji) + '(.*)')).filter(emptyStringFilter);

            lastUsedKanjiIndex = index;
            replacementText += replacementTemplate.replace('$1', kanji[index]).replace('$2', splitFurigana[0]);
            replacementText += currentNonKanji;

            furiganaText = splitFurigana[1];
          });
          if (furiganaText !== undefined && lastUsedKanjiIndex + 1 < kanji.length) {
            replacementText += replacementTemplate.replace('$1', kanji[lastUsedKanjiIndex + 1]).replace('$2', furiganaText);
          } else if (furiganaText !== undefined) {
            return replacementTemplate.replace('$1', wordText).replace('$2', originalFuriganaText);
          } else if (lastUsedKanjiIndex + 1 < kanji.length) {
            replacementText += kanji[lastUsedKanjiIndex + 1];
          }
          return replacementText;
        }
      } else {
        return match;
      }
    });
  });

  if (!options.furiganaStrictMode) {
    if (options.furiganaAutoBracketSets !== previousAutoBracketSets) {
      updateAutoRegexList(options.furiganaAutoBracketSets);
    }
    autoRegexList.forEach(regex => {
      text = text.replace(regex, (match, preWordTerminator, wordKanji, wordKanaSuffix, furiganaText, offset, mainText) => {
        if (match.indexOf('\\') === -1) {
          if (options.furiganaPatternMatching) {
            let rubies = [];

            let furigana = furiganaText;

            //put in if
            let stem = (' ' + wordKanaSuffix).slice(1);
            for (let i = furiganaText.length - 1; i >= 0; i--) {
              if (wordKanaSuffix.length === 0) {
                furigana = furiganaText.substring(0, i + 1);
                break;
              }
              if (furiganaText[i] !== wordKanaSuffix.slice(-1)) {
                furigana = furiganaText.substring(0, i + 1);
                break;
              }
              wordKanaSuffix = wordKanaSuffix.slice(0, -1);
            }

            if (furiganaSeperators.split('').reduce(
              (noSeperator, seperator) => {
                return noSeperator && (furigana.indexOf(seperator) === -1);
              },
              true
            )) {
              rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
            } else {
              let kanaParts = furigana.split(seperatorRegex);
              let kanji = wordKanji.split('');
              if (kanaParts.length !== kanji.length) {
                rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
              } else {
                for (let i = 0; i < wordKanji.length; i++) {
                  rubies.push(replacementTemplate.replace('$1', wordKanji).replace('$2', kanaParts[i]));
                }
              }
            }

            return preWordTerminator + rubies.join('') + stem;
          } else {
            return preWordTerminator + replacementTemplate.replace('$1', wordKanji).replace('$2', furiganaText) + wordKanaSuffix;
          }
        } else {
          return match;
        }
      });
    });
  }
  return text;
}

function handleEscapedSpecialBrackets(text) {
  // By default 【 and 】 cannot be escaped in markdown, this will remove backslashes from in front of them to give that effect.
  return text.replace(/\\([【】])/g, '$1');
}

export function setup(helper) {
  helper.whiteList([
    'ruby',
    'rt',
    'rp'
  ]);

  helper.addPreProcessor(text => {
    return handleEscapedSpecialBrackets(addFurigana(text, helper.getOptions()));
  });
}
<|endoftext|>


<commit_before>/* jslint browser: true, jquery: true, asi: true */
/* globals google: false */
(function($) {
  'use strict'

  // Appear-on-scroll Animation Support
  //
  // Requires:
  // Animate.css - https://daneden.github.io/animate.css/
  // jquery.appear - https://github.com/bas2k/jquery.appear/
  // jquery.countTo - https://github.com/mhuggins/jquery-countTo/
  //
  // Define animation blocks like so:
  //
  //

  //
  // Count to a number using this inside .animated like this:
  //
  //

  //       4800
  //

  //
  // The block will animate when it is scrolled into view.

  // Stop animations on small screens
  if ($(window).width() < 768) {
    $('.animated').removeClass('animated transparent')
  }

  function animate(element, animation) {
    element.addClass(animation + " opaque").removeClass('transparent')
    if (element.hasClass('counter')) {
      element.find('.timer').countTo()
    }
  }

  $('.animated').addClass('transparent').appear(function() {
    var element = $(this)
    var animation = element.data('animation')
    var animationDelay = element.data('delay')

    if (animationDelay) {
      setTimeout(function() {
        animate(element, animation)
      }, animationDelay)
    } else {
      animate(element, animation)
    }
  }, {accY: -150})

  // jQuery for page scrolling feature - requires jQuery Easing plugin
  $('a.page-scroll').bind('click', function(event) {
    var anchor = $(this)
    $('html, body').stop().animate({
      scrollTop: $(anchor.attr('href')).offset().top - $('.navbar-custom').height() * 1.2
    }, 1000, 'easeInOutExpo')
    event.preventDefault()
  })

  // Closes the Responsive Menu on Menu Item Click
  $('.navbar-collapse ul li a').click(function() {
    if ($(this).attr('class') !== 'dropdown-toggle active' &&
        $(this).attr('class') !== 'dropdown-toggle') {
      $('.navbar-toggle:visible').click()
    }
  })

  // Google Maps
  if (typeof google !== 'undefined') {
    var map = null
    var mapMarker = null

    // When the window has finished loading create our google map below
    google.maps.event.addDomListener(window, 'load', function() {

      // Get the HTML DOM element that will contain your map
      // We are using a div with id="map" seen below in the
      var mapElement = document.getElementById('map')

      // Get the marker's lat and long from the DOM
      var mapData = $(mapElement).data()
      mapMarker = new google.maps.LatLng(
        parseFloat(mapData.markerLat), parseFloat(mapData.markerLng))

      // Basic options for a simple Google Map`
      // For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions
      var mapOptions = {
        zoom: 6,
        center: mapMarker,
        mapTypeId: google.maps.MapTypeId.HYBRID,
        disableDefaultUI: true,
        scrollwheel: false,
        draggable: true
      }

      // Create the Google Map using out element and options defined above
      map = new google.maps.Map(mapElement, mapOptions)

      // Custom Map Marker icon
      var image = 'https://www.jcu.edu.au/__data/assets/file/0007/285460/marker.svg'  // Mega hack for quick Squiz Matrix URL
      var locationMarker = new google.maps.Marker({
        position: mapMarker,
        map: map,
        icon: image
      })
      locationMarker.addListener('click', function() {
        map.setCenter(mapMarker)
        map.setZoom(16)
      })
    })
    google.maps.event.addDomListener(window, 'resize', function() {
      map.setCenter(mapMarker)
    })
  }
})(jQuery)
<commit_msg>Sane defaults for all the map settings in Landing design<commit_after>/* jslint browser: true, jquery: true, asi: true */
/* globals google: false */
(function($) {
  'use strict'

  // Appear-on-scroll Animation Support
  //
  // Requires:
  // Animate.css - https://daneden.github.io/animate.css/
  // jquery.appear - https://github.com/bas2k/jquery.appear/
  // jquery.countTo - https://github.com/mhuggins/jquery-countTo/
  //
  // Define animation blocks like so:
  //
  //

  //
  // Count to a number using this inside .animated like this:
  //
  //

  //       4800
  //

  //
  // The block will animate when it is scrolled into view.

  // Stop animations on small screens
  if ($(window).width() < 768) {
    $('.animated').removeClass('animated transparent')
  }

  function animate(element, animation) {
    element.addClass(animation + " opaque").removeClass('transparent')
    if (element.hasClass('counter')) {
      element.find('.timer').countTo()
    }
  }

  $('.animated').addClass('transparent').appear(function() {
    var element = $(this)
    var animation = element.data('animation')
    var animationDelay = element.data('delay')

    if (animationDelay) {
      setTimeout(function() {
        animate(element, animation)
      }, animationDelay)
    } else {
      animate(element, animation)
    }
  }, {accY: -150})

  // jQuery for page scrolling feature - requires jQuery Easing plugin
  $('a.page-scroll').bind('click', function(event) {
    var anchor = $(this)
    $('html, body').stop().animate({
      scrollTop: $(anchor.attr('href')).offset().top - $('.navbar-custom').height() * 1.2
    }, 1000, 'easeInOutExpo')
    event.preventDefault()
  })

  // Closes the Responsive Menu on Menu Item Click
  $('.navbar-collapse ul li a').click(function() {
    if ($(this).attr('class') !== 'dropdown-toggle active' &&
        $(this).attr('class') !== 'dropdown-toggle') {
      $('.navbar-toggle:visible').click()
    }
  })

  // Google Maps
  if (typeof google !== 'undefined') {
    var map = null
    var mapMarker = null

    // When the window has finished loading create our google map below
    google.maps.event.addDomListener(window, 'load', function() {

      // Get the HTML DOM element that will contain your map
      // We are using a div with id="map" seen below in the
      var mapElement = document.getElementById('map')

      // Get the marker's lat and long from the DOM
      var mapData = $(mapElement).data()
      mapMarker = new google.maps.LatLng(
        parseFloat(mapData.markerLat || -25.608539), parseFloat(mapData.markerLng || 134.361731))

      // Basic options for a simple Google Map`
      // For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions
      var mapOptions = {
        zoom: mapData.initialZoom || 6,
        center: mapMarker,
        mapTypeId: mapData.mapTypeId || google.maps.MapTypeId.HYBRID,
        disableDefaultUI: mapData.disableDefaultUI !== false,
        scrollwheel: mapData.scrollwheel !== false,
        draggable: mapData.draggable !== false
      }

      // Create the Google Map using out element and options defined above
      map = new google.maps.Map(mapElement, mapOptions)

      // Custom Map Marker icon
      var image = mapData.markerUrl || 'https://www.jcu.edu.au/__data/assets/file/0007/285460/marker.svg'  // Mega hack for quick Squiz Matrix URL
      var locationMarker = new google.maps.Marker({
        position: mapMarker,
        map: map,
        icon: image
      })
      locationMarker.addListener('click', function() {
        map.setCenter(mapMarker)
        map.setZoom(mapData.fullZoom || 16)
      })
    })
    google.maps.event.addDomListener(window, 'resize', function() {
      map.setCenter(mapMarker)
    })
  }
})(jQuery)
<|endoftext|>