<commit_before>'use strict';

/*
 * A module for adding new a routing system Angular 1.
 */
angular.module('ngNewRouter', [])
  .factory('$router', routerFactory)
  .value('$routeParams', {})
  .factory('$componentMapper', $componentMapperFactory)
  .provider('$pipeline', pipelineProvider)
  .factory('$$pipeline', privatePipelineFactory)
  .factory('$setupRoutersStep', setupRoutersStepFactory)
  .factory('$initLocalsStep', initLocalsStepFactory)
  .factory('$runCanDeactivateHookStep', runCanDeactivateHookStepFactory)
  .factory('$runCanActivateHookStep', runCanActivateHookStepFactory)
  .factory('$loadTemplatesStep', loadTemplatesStepFactory)
  .value('$activateStep', activateStepValue)
  .directive('ngOutlet', ngOutletDirective)
  .directive('ngOutlet', ngOutletFillContentDirective)
  .directive('ngLink', ngLinkDirective)
  .directive('a', anchorLinkDirective)

var NOOP_CONTROLLER = function(){};

/*
 * A module for inspecting controller constructors
 */
angular.module('ng')
  .provider('$controllerIntrospector', $controllerIntrospectorProvider)
  .config(controllerProviderDecorator);

/*
 * decorates with routing info
 */
function controllerProviderDecorator($controllerProvider, $controllerIntrospectorProvider) {
  var register = $controllerProvider.register;
  $controllerProvider.register = function (name, ctrl) {
    $controllerIntrospectorProvider.register(name, ctrl);
    return register.apply(this, arguments);
  };
}

/*
 * private service that holds route mappings for each controller
 */
function $controllerIntrospectorProvider() {
  var controllers = [];
  var controllersByName = {};
  var onControllerRegistered = null;
  return {
    register: function (name, constructor) {
      if (angular.isArray(constructor)) {
        constructor = constructor[constructor.length - 1];
      }
      controllersByName[name] = constructor;
      if (constructor.$routeConfig) {
        if (onControllerRegistered) {
          onControllerRegistered(name, constructor.$routeConfig);
        } else {
          controllers.push({name: name, config: constructor.$routeConfig});
        }
      }
    },
    $get: ['$componentMapper', function ($componentMapper) {
      var fn = function (newOnControllerRegistered) {
        onControllerRegistered = function (name, constructor) {
          name = $componentMapper.component(name);
          return newOnControllerRegistered(name, constructor);
        };
        while(controllers.length > 0) {
          var rule = controllers.pop();
          onControllerRegistered(rule.name, rule.config);
        }
      };

      fn.getTypeByName = function (name) {
        return controllersByName[name];
      };

      return fn;
    }]
  }
}

function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controllerIntrospector) {

  $controllerIntrospector(function (name, config) {
    $$grammar.config(name, config);
  });

  $rootScope.$watch(function () {
    return $location.path();
  }, function (newUrl) {
    $$rootRouter.navigate(newUrl);
  });

  var nav = $$rootRouter.navigate;
  $$rootRouter.navigate = function (url) {
    return nav.call(this, url).then(function (newUrl) {
      if (newUrl) {
        $location.path(newUrl);
      }
    });
  }

  return $$rootRouter;
}

/**
 * @name ngOutlet
 *
 * @description
 * An ngOutlet is where resolved content goes.
 *
 * ## Use
 *
 * ```html
 * <div ng-outlet="name"></div>
 * ```
 *
 * The value for the `ngOutlet` attribute is optional.
 */
function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $controller) {
  var rootRouter = $router;

  return {
    restrict: 'AE',
    transclude: 'element',
    terminal: true,
    priority: 400,
    require: ['?^^ngOutlet', 'ngOutlet'],
    link: outletLink,
    controller: function() {},
    controllerAs: '$$ngOutlet'
  };

  function invoke(method, context, instruction) {
    return $injector.invoke(method, context, instruction.locals);
  }

  function outletLink(scope, $element, attrs, ctrls, $transclude) {
    var outletName = attrs.ngOutlet || 'default',
        parentCtrl = ctrls[0],
        myCtrl = ctrls[1],
        router = (parentCtrl && parentCtrl.$$router) || rootRouter;

    var currentScope,
        newScope,
        currentController,
        currentElement,
        previousLeaveAnimation,
        previousInstruction;

    function cleanupLastView() {
      if (previousLeaveAnimation) {
        $animate.cancel(previousLeaveAnimation);
        previousLeaveAnimation = null;
      }

      if (currentScope) {
        currentScope.$destroy();
        currentScope = null;
      }
      if (currentElement) {
        previousLeaveAnimation = $animate.leave(currentElement);
        previousLeaveAnimation.then(function() {
          previousLeaveAnimation = null;
        });
        currentElement = null;
      }
    }

    router.registerOutlet({
      canDeactivate: function(instruction) {
        if (currentController && currentController.canDeactivate) {
          return invoke(currentController.canDeactivate, currentController, instruction);
        }
        return true;
      },
      activate: function(instruction) {
        var nextInstruction = serializeInstruction(instruction);
        if (nextInstruction === previousInstruction) {
          return;
        }

        var controllerConstructor = instruction.controllerConstructor;

        if (!instruction.locals.$scope) {
          instruction.locals.$scope = scope.$new();
        }
        newScope = instruction.locals.$scope;

        if (controllerConstructor === NOOP_CONTROLLER) {
          console.warn && console.warn('Could not find controller for', $componentMapper.controllerName(instruction.component));
        }
        var ctrl = $controller(controllerConstructor, instruction.locals);
        instruction.controllerAs = $componentMapper.controllerAs(instruction.component);
        instruction.controller = ctrl;

        myCtrl.$$router = instruction.router;
        myCtrl.$$template = instruction.template;
        var controllerAs = instruction.controllerAs || instruction.component;
        var clone = $transclude(newScope, function(clone) {
          $animate.enter(clone, null, currentElement || $element);
          cleanupLastView();
        });

        var newController = instruction.controller;
        newScope[controllerAs] = newController;

        var result;
        if (currentController && currentController.deactivate) {
          result = $q.when(invoke(currentController.deactivate, currentController, instruction));
        }

        currentController = newController;

        currentElement = clone;
        currentScope = newScope;

        previousInstruction = nextInstruction;

        // finally, run the hook
        if (newController.activate) {
          var activationResult = $q.when(invoke(newController.activate, newController, instruction));
          if (result) {
            return result.then(activationResult);
          } else {
            return activationResult;
          }
        }
        return result;
      }
    }, outletName);
  }

  // TODO: how best to serialize?
  function serializeInstruction(instruction) {
    return JSON.stringify({
      path: instruction.path,
      component: instruction.component,
      params: Object.keys(instruction.params).reduce(function (acc, key) {
        return (key !== 'childRoute' && (acc[key] = instruction.params[key])), acc;
      }, {})
    });
  }
}

function ngOutletFillContentDirective($compile) {
  return {
    restrict: 'EA',
    priority: -400,
    require: 'ngOutlet',
    link: function(scope, $element, attrs, ctrl) {
      var template = ctrl.$$template;
      $element.html(template);
      var link = $compile($element.contents());
      link(scope);
    }
  };
}

function makeComponentString(name) {
  return [
    '<router-component component-name="', name, '">',
    '</router-component>'
  ].join('');
}

var LINK_MICROSYNTAX_RE = /^(.+?)(?:\((.*)\))?$/;
/**
 * @name ngLink
 * @description
 * Lets you link to different parts of the app, and automatically generates hrefs.
 *
 * ## Use
 * The directive uses a simple syntax: `ng-link="componentName({ param: paramValue })"`
 *
 * ## Example
 *
 * ```js
 * angular.module('myApp', ['ngFuturisticRouter'])
 *   .controller('AppController', ['$router', function($router) {
 *     $router.config({ path: '/user/:id' component: 'user' });
 *     this.user = { name: 'Brian', id: 123 };
 *   });
 * ```
 *
 * ```html
 * <div ng-controller="AppController as app">
 *   <a ng-link="user({id: app.user.id})">{{app.user.name}}</a>
 * </div>
 * ```
 */
function ngLinkDirective($router, $location, $parse) {
  var rootRouter = $router;

  return {
    require: '?^^ngOutlet',
    restrict: 'A',
    link: ngLinkDirectiveLinkFn
  };

  function ngLinkDirectiveLinkFn(scope, elt, attrs, ctrl) {
    var router = (ctrl && ctrl.$$router) || rootRouter;
    if (!router) {
      return;
    }

    var link = attrs.ngLink || '';
    var parts = link.match(LINK_MICROSYNTAX_RE);
    var routeName = parts[1];
    var routeParams = parts[2];
    var url;

    if (routeParams) {
      var routeParamsGetter = $parse(routeParams);
      // we can avoid adding a watcher if it's a literal
      if (routeParamsGetter.constant) {
        var params = routeParamsGetter();
        url = '.' + router.generate(routeName, params);
        elt.attr('href', url);
      } else {
        scope.$watch(function() {
          return routeParamsGetter(scope);
        }, function(params) {
          url = '.' + router.generate(routeName, params);
          elt.attr('href', url);
        }, true);
      }
    } else {
      url = '.' + router.generate(routeName);
      elt.attr('href', url);
    }
  }
}

function anchorLinkDirective($router) {
  return {
    restrict: 'E',
    link: function(scope, element) {
      // If the linked element is not an anchor tag anymore, do nothing
      if (element[0].nodeName.toLowerCase() !== 'a') return;

      // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
      var hrefAttrName = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
                     'xlink:href' : 'href';

      element.on('click', function(event) {
        if (event.which !== 1)
          return;

        var href = element.attr(hrefAttrName);
        if (!href) {
          event.preventDefault();
        }
        if ($router.recognize(href)) {
          $router.navigate(href);
          event.preventDefault();
        }
      });
    }
  }
}

function setupRoutersStepFactory() {
  return function (instruction) {
    return instruction.router.makeDescendantRouters(instruction);
  }
}

//TODO: rename to "normalize" step
/*
 * $initLocalsStep
 */
function initLocalsStepFactory($componentMapper, $controllerIntrospector) {
  return function initLocals(instruction) {
    return instruction.router.traverseInstruction(instruction, function(instruction) {
      if (typeof instruction.component === 'function') {
        instruction.controllerConstructor = instruction.component;
      } else {
        var controllerName = $componentMapper.controllerName(instruction.component);
        if (typeof controllerName === 'function') {
          instruction.controllerConstructor = controllerName;
        } else {
          instruction.controllerConstructor = $controllerIntrospector.getTypeByName(controllerName) || NOOP_CONTROLLER;
        }
      }
      return instruction.locals = {
        $router: instruction.router,
        $routeParams: (instruction.params || {})
      };
    });
  }
}

function runCanDeactivateHookStepFactory() {
  return function runCanDeactivateHook(instruction) {
    return instruction.router.canDeactivateOutlets(instruction);
  };
}

function runCanActivateHookStepFactory($injector) {

  function invoke(method, context, instruction) {
    return $injector.invoke(method, context, {
      $routeParams: instruction.params
    });
  }

  return function runCanActivateHook(instruction) {
    return instruction.router.traverseInstruction(instruction, function(instruction) {
      var controllerConstructor = instruction.controllerConstructor;
      return !controllerConstructor.canActivate || invoke(controllerConstructor.canActivate, null, instruction);
    });
  }
}

function loadTemplatesStepFactory($componentMapper, $templateRequest) {
  return function loadTemplates(instruction) {
    return instruction.router.traverseInstruction(instruction, function(instruction) {
      var componentTemplateUrl = $componentMapper.template(instruction.component);
      return $templateRequest(componentTemplateUrl).then(function (templateHtml) {
        return instruction.template = templateHtml;
      });
    });
  };
}

function activateStepValue(instruction) {
  return instruction.router.activateOutlets(instruction);
}

function pipelineProvider() {
  var stepConfiguration;

  var protoStepConfiguration = [
    '$setupRoutersStep',
    '$initLocalsStep',
    '$runCanDeactivateHookStep',
    '$runCanActivateHookStep',
    '$loadTemplatesStep',
    '$activateStep'
  ];

  return {
    steps: protoStepConfiguration.slice(0),
    config: function (newConfig) {
      protoStepConfiguration = newConfig;
    },
    $get: function ($injector, $q) {
      stepConfiguration = protoStepConfiguration.map(function (step) {
        return $injector.get(step);
      });
      return {
        process: function(instruction) {
          // make a copy
          var steps = stepConfiguration.slice(0);

          function processOne(result) {
            if (steps.length === 0) {
              return result;
            }
            var step = steps.shift();
            return $q.when(step(instruction)).then(processOne);
          }

          return processOne();
        }
      }
    }
  };
}

/**
 * @name $componentMapper
 * @description
 *
 * This lets you configure conventions for what controllers are named and where to load templates from.
 *
 * The default behavior is to dasherize and serve from `./components`. A component called `myWidget`
 * uses a controller named `MyWidgetController` and a template loaded from `./components/my-widget/my-widget.html`.
 *
 * A component is:
 * - a controller
 * - a template
 * - an optional router
 *
 * This service makes it easy to group all of them into a single concept.
 */
function $componentMapperFactory() {

  var DEFAULT_SUFFIX = 'Controller';

  var componentToCtrl = function componentToCtrlDefault(name) {
    return name[0].toUpperCase() + name.substr(1) + DEFAULT_SUFFIX;
  };

  var componentToTemplate = function componentToTemplateDefault(name) {
    var dashName = dashCase(name);
    return './components/' + dashName + '/' + dashName + '.html';
  };

  var ctrlToComponent = function ctrlToComponentDefault(name) {
    return name[0].toLowerCase() + name.substr(1, name.length - DEFAULT_SUFFIX.length - 1);
  };

  var componentToControllerAs = function componentToControllerAsDefault(name) {
    return name;
  };

  return {
    controllerName: function (name) {
      return componentToCtrl(name);
    },

    controllerAs: function (name) {
      return componentToControllerAs(name);
    },

    template: function (name) {
      return componentToTemplate(name);
    },

    component: function (name) {
      return ctrlToComponent(name);
    },

    /**
     * @name $componentMapper#setCtrlNameMapping
     * @description takes a function for mapping component names to component controller names
     */
    setCtrlNameMapping: function(newFn) {
      componentToCtrl = newFn;
      return this;
    },

    /**
     * @name $componentMapper#setCtrlAsMapping
     * @description takes a function for mapping component names to controllerAs name in the template
     */
    setCtrlAsMapping: function(newFn) {
      componentToControllerAs = newFn;
      return this;
    },

    /**
     * @name $componentMapper#setComponentFromCtrlMapping
     * @description takes a function for mapping component controller names to component names
     */
    setComponentFromCtrlMapping: function (newFn) {
      ctrlToComponent = newFn;
      return this;
    },

    /**
     * @name $componentMapper#setTemplateMapping
     * @description takes a function for mapping component names to component template URLs
     */
    setTemplateMapping: function(newFn) {
      componentToTemplate = newFn;
      return this;
    }
  };
}

// this is a hack as a result of the build system used to transpile
function privatePipelineFactory($pipeline) {
  return $pipeline;
}

function dashCase(str) {
  return str.replace(/([A-Z])/g, function ($1) {
    return '-' + $1.toLowerCase();
  });
}
<commit_msg>fix($controllerIntrospectorProvider): fix instantiating of controllers that use the array DI notation<commit_after>'use strict';

/*
 * A module for adding new a routing system Angular 1.
 */
angular.module('ngNewRouter', [])
  .factory('$router', routerFactory)
  .value('$routeParams', {})
  .factory('$componentMapper', $componentMapperFactory)
  .provider('$pipeline', pipelineProvider)
  .factory('$$pipeline', privatePipelineFactory)
  .factory('$setupRoutersStep', setupRoutersStepFactory)
  .factory('$initLocalsStep', initLocalsStepFactory)
  .factory('$runCanDeactivateHookStep', runCanDeactivateHookStepFactory)
  .factory('$runCanActivateHookStep', runCanActivateHookStepFactory)
  .factory('$loadTemplatesStep', loadTemplatesStepFactory)
  .value('$activateStep', activateStepValue)
  .directive('ngOutlet', ngOutletDirective)
  .directive('ngOutlet', ngOutletFillContentDirective)
  .directive('ngLink', ngLinkDirective)
  .directive('a', anchorLinkDirective)

var NOOP_CONTROLLER = function(){};

/*
 * A module for inspecting controller constructors
 */
angular.module('ng')
  .provider('$controllerIntrospector', $controllerIntrospectorProvider)
  .config(controllerProviderDecorator);

/*
 * decorates with routing info
 */
function controllerProviderDecorator($controllerProvider, $controllerIntrospectorProvider) {
  var register = $controllerProvider.register;
  $controllerProvider.register = function (name, ctrl) {
    $controllerIntrospectorProvider.register(name, ctrl);
    return register.apply(this, arguments);
  };
}

/*
 * private service that holds route mappings for each controller
 */
function $controllerIntrospectorProvider() {
  var controllers = [];
  var constructorsByName = {};
  var onControllerRegistered = null;

  function getController(constructor) {
    return angular.isArray(constructor) ? constructor[constructor.length - 1] : constructor;
  }

  return {
    register: function (name, constructor) {
      var controller = getController(constructor);
      constructorsByName[name] = constructor;
      if (controller.$routeConfig) {
        if (onControllerRegistered) {
          onControllerRegistered(name, controller.$routeConfig);
        } else {
          controllers.push({name: name, config: controller.$routeConfig});
        }
      }
    },
    $get: ['$componentMapper', function ($componentMapper) {
      var fn = function (newOnControllerRegistered) {
        onControllerRegistered = function (name, constructor) {
          name = $componentMapper.component(name);
          return newOnControllerRegistered(name, constructor);
        };
        while(controllers.length > 0) {
          var rule = controllers.pop();
          onControllerRegistered(rule.name, rule.config);
        }
      };

      fn.getTypeByName = function (name) {
        return constructorsByName[name];
      };

      return fn;
    }]
  }
}

function routerFactory($$rootRouter, $rootScope, $location, $$grammar, $controllerIntrospector) {

  $controllerIntrospector(function (name, config) {
    $$grammar.config(name, config);
  });

  $rootScope.$watch(function () {
    return $location.path();
  }, function (newUrl) {
    $$rootRouter.navigate(newUrl);
  });

  var nav = $$rootRouter.navigate;
  $$rootRouter.navigate = function (url) {
    return nav.call(this, url).then(function (newUrl) {
      if (newUrl) {
        $location.path(newUrl);
      }
    });
  }

  return $$rootRouter;
}

/**
 * @name ngOutlet
 *
 * @description
 * An ngOutlet is where resolved content goes.
 *
 * ## Use
 *
 * ```html
 * <div ng-outlet="name"></div>
 * ```
 *
 * The value for the `ngOutlet` attribute is optional.
 */
function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $controller) {
  var rootRouter = $router;

  return {
    restrict: 'AE',
    transclude: 'element',
    terminal: true,
    priority: 400,
    require: ['?^^ngOutlet', 'ngOutlet'],
    link: outletLink,
    controller: function() {},
    controllerAs: '$$ngOutlet'
  };

  function invoke(method, context, instruction) {
    return $injector.invoke(method, context, instruction.locals);
  }

  function outletLink(scope, $element, attrs, ctrls, $transclude) {
    var outletName = attrs.ngOutlet || 'default',
        parentCtrl = ctrls[0],
        myCtrl = ctrls[1],
        router = (parentCtrl && parentCtrl.$$router) || rootRouter;

    var currentScope,
        newScope,
        currentController,
        currentElement,
        previousLeaveAnimation,
        previousInstruction;

    function cleanupLastView() {
      if (previousLeaveAnimation) {
        $animate.cancel(previousLeaveAnimation);
        previousLeaveAnimation = null;
      }

      if (currentScope) {
        currentScope.$destroy();
        currentScope = null;
      }
      if (currentElement) {
        previousLeaveAnimation = $animate.leave(currentElement);
        previousLeaveAnimation.then(function() {
          previousLeaveAnimation = null;
        });
        currentElement = null;
      }
    }

    router.registerOutlet({
      canDeactivate: function(instruction) {
        if (currentController && currentController.canDeactivate) {
          return invoke(currentController.canDeactivate, currentController, instruction);
        }
        return true;
      },
      activate: function(instruction) {
        var nextInstruction = serializeInstruction(instruction);
        if (nextInstruction === previousInstruction) {
          return;
        }

        var controllerConstructor = instruction.controllerConstructor;

        if (!instruction.locals.$scope) {
          instruction.locals.$scope = scope.$new();
        }
        newScope = instruction.locals.$scope;

        if (controllerConstructor === NOOP_CONTROLLER) {
          console.warn && console.warn('Could not find controller for', $componentMapper.controllerName(instruction.component));
        }
        var ctrl = $controller(controllerConstructor, instruction.locals);
        instruction.controllerAs = $componentMapper.controllerAs(instruction.component);
        instruction.controller = ctrl;

        myCtrl.$$router = instruction.router;
        myCtrl.$$template = instruction.template;
        var controllerAs = instruction.controllerAs || instruction.component;
        var clone = $transclude(newScope, function(clone) {
          $animate.enter(clone, null, currentElement || $element);
          cleanupLastView();
        });

        var newController = instruction.controller;
        newScope[controllerAs] = newController;

        var result;
        if (currentController && currentController.deactivate) {
          result = $q.when(invoke(currentController.deactivate, currentController, instruction));
        }

        currentController = newController;

        currentElement = clone;
        currentScope = newScope;

        previousInstruction = nextInstruction;

        // finally, run the hook
        if (newController.activate) {
          var activationResult = $q.when(invoke(newController.activate, newController, instruction));
          if (result) {
            return result.then(activationResult);
          } else {
            return activationResult;
          }
        }
        return result;
      }
    }, outletName);
  }

  // TODO: how best to serialize?
  function serializeInstruction(instruction) {
    return JSON.stringify({
      path: instruction.path,
      component: instruction.component,
      params: Object.keys(instruction.params).reduce(function (acc, key) {
        return (key !== 'childRoute' && (acc[key] = instruction.params[key])), acc;
      }, {})
    });
  }
}

function ngOutletFillContentDirective($compile) {
  return {
    restrict: 'EA',
    priority: -400,
    require: 'ngOutlet',
    link: function(scope, $element, attrs, ctrl) {
      var template = ctrl.$$template;
      $element.html(template);
      var link = $compile($element.contents());
      link(scope);
    }
  };
}

function makeComponentString(name) {
  return [
    '<router-component component-name="', name, '">',
    '</router-component>'
  ].join('');
}

var LINK_MICROSYNTAX_RE = /^(.+?)(?:\((.*)\))?$/;
/**
 * @name ngLink
 * @description
 * Lets you link to different parts of the app, and automatically generates hrefs.
 *
 * ## Use
 * The directive uses a simple syntax: `ng-link="componentName({ param: paramValue })"`
 *
 * ## Example
 *
 * ```js
 * angular.module('myApp', ['ngFuturisticRouter'])
 *   .controller('AppController', ['$router', function($router) {
 *     $router.config({ path: '/user/:id' component: 'user' });
 *     this.user = { name: 'Brian', id: 123 };
 *   });
 * ```
 *
 * ```html
 * <div ng-controller="AppController as app">
 *   <a ng-link="user({id: app.user.id})">{{app.user.name}}</a>
 * </div>
 * ```
 */
function ngLinkDirective($router, $location, $parse) {
  var rootRouter = $router;

  return {
    require: '?^^ngOutlet',
    restrict: 'A',
    link: ngLinkDirectiveLinkFn
  };

  function ngLinkDirectiveLinkFn(scope, elt, attrs, ctrl) {
    var router = (ctrl && ctrl.$$router) || rootRouter;
    if (!router) {
      return;
    }

    var link = attrs.ngLink || '';
    var parts = link.match(LINK_MICROSYNTAX_RE);
    var routeName = parts[1];
    var routeParams = parts[2];
    var url;

    if (routeParams) {
      var routeParamsGetter = $parse(routeParams);
      // we can avoid adding a watcher if it's a literal
      if (routeParamsGetter.constant) {
        var params = routeParamsGetter();
        url = '.' + router.generate(routeName, params);
        elt.attr('href', url);
      } else {
        scope.$watch(function() {
          return routeParamsGetter(scope);
        }, function(params) {
          url = '.' + router.generate(routeName, params);
          elt.attr('href', url);
        }, true);
      }
    } else {
      url = '.' + router.generate(routeName);
      elt.attr('href', url);
    }
  }
}

function anchorLinkDirective($router) {
  return {
    restrict: 'E',
    link: function(scope, element) {
      // If the linked element is not an anchor tag anymore, do nothing
      if (element[0].nodeName.toLowerCase() !== 'a') return;

      // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
      var hrefAttrName = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
                     'xlink:href' : 'href';

      element.on('click', function(event) {
        if (event.which !== 1)
          return;

        var href = element.attr(hrefAttrName);
        if (!href) {
          event.preventDefault();
        }
        if ($router.recognize(href)) {
          $router.navigate(href);
          event.preventDefault();
        }
      });
    }
  }
}

function setupRoutersStepFactory() {
  return function (instruction) {
    return instruction.router.makeDescendantRouters(instruction);
  }
}

//TODO: rename to "normalize" step
/*
 * $initLocalsStep
 */
function initLocalsStepFactory($componentMapper, $controllerIntrospector) {
  return function initLocals(instruction) {
    return instruction.router.traverseInstruction(instruction, function(instruction) {
      if (typeof instruction.component === 'function') {
        instruction.controllerConstructor = instruction.component;
      } else {
        var controllerName = $componentMapper.controllerName(instruction.component);
        if (typeof controllerName === 'function') {
          instruction.controllerConstructor = controllerName;
        } else {
          instruction.controllerConstructor = $controllerIntrospector.getTypeByName(controllerName) || NOOP_CONTROLLER;
        }
      }
      return instruction.locals = {
        $router: instruction.router,
        $routeParams: (instruction.params || {})
      };
    });
  }
}

function runCanDeactivateHookStepFactory() {
  return function runCanDeactivateHook(instruction) {
    return instruction.router.canDeactivateOutlets(instruction);
  };
}

function runCanActivateHookStepFactory($injector) {

  function invoke(method, context, instruction) {
    return $injector.invoke(method, context, {
      $routeParams: instruction.params
    });
  }

  return function runCanActivateHook(instruction) {
    return instruction.router.traverseInstruction(instruction, function(instruction) {
      var controllerConstructor = instruction.controllerConstructor;
      return !controllerConstructor.canActivate || invoke(controllerConstructor.canActivate, null, instruction);
    });
  }
}

function loadTemplatesStepFactory($componentMapper, $templateRequest) {
  return function loadTemplates(instruction) {
    return instruction.router.traverseInstruction(instruction, function(instruction) {
      var componentTemplateUrl = $componentMapper.template(instruction.component);
      return $templateRequest(componentTemplateUrl).then(function (templateHtml) {
        return instruction.template = templateHtml;
      });
    });
  };
}

function activateStepValue(instruction) {
  return instruction.router.activateOutlets(instruction);
}

function pipelineProvider() {
  var stepConfiguration;

  var protoStepConfiguration = [
    '$setupRoutersStep',
    '$initLocalsStep',
    '$runCanDeactivateHookStep',
    '$runCanActivateHookStep',
    '$loadTemplatesStep',
    '$activateStep'
  ];

  return {
    steps: protoStepConfiguration.slice(0),
    config: function (newConfig) {
      protoStepConfiguration = newConfig;
    },
    $get: function ($injector, $q) {
      stepConfiguration = protoStepConfiguration.map(function (step) {
        return $injector.get(step);
      });
      return {
        process: function(instruction) {
          // make a copy
          var steps = stepConfiguration.slice(0);

          function processOne(result) {
            if (steps.length === 0) {
              return result;
            }
            var step = steps.shift();
            return $q.when(step(instruction)).then(processOne);
          }

          return processOne();
        }
      }
    }
  };
}

/**
 * @name $componentMapper
 * @description
 *
 * This lets you configure conventions for what controllers are named and where to load templates from.
 *
 * The default behavior is to dasherize and serve from `./components`. A component called `myWidget`
 * uses a controller named `MyWidgetController` and a template loaded from `./components/my-widget/my-widget.html`.
 *
 * A component is:
 * - a controller
 * - a template
 * - an optional router
 *
 * This service makes it easy to group all of them into a single concept.
 */
function $componentMapperFactory() {

  var DEFAULT_SUFFIX = 'Controller';

  var componentToCtrl = function componentToCtrlDefault(name) {
    return name[0].toUpperCase() + name.substr(1) + DEFAULT_SUFFIX;
  };

  var componentToTemplate = function componentToTemplateDefault(name) {
    var dashName = dashCase(name);
    return './components/' + dashName + '/' + dashName + '.html';
  };

  var ctrlToComponent = function ctrlToComponentDefault(name) {
    return name[0].toLowerCase() + name.substr(1, name.length - DEFAULT_SUFFIX.length - 1);
  };

  var componentToControllerAs = function componentToControllerAsDefault(name) {
    return name;
  };

  return {
    controllerName: function (name) {
      return componentToCtrl(name);
    },

    controllerAs: function (name) {
      return componentToControllerAs(name);
    },

    template: function (name) {
      return componentToTemplate(name);
    },

    component: function (name) {
      return ctrlToComponent(name);
    },

    /**
     * @name $componentMapper#setCtrlNameMapping
     * @description takes a function for mapping component names to component controller names
     */
    setCtrlNameMapping: function(newFn) {
      componentToCtrl = newFn;
      return this;
    },

    /**
     * @name $componentMapper#setCtrlAsMapping
     * @description takes a function for mapping component names to controllerAs name in the template
     */
    setCtrlAsMapping: function(newFn) {
      componentToControllerAs = newFn;
      return this;
    },

    /**
     * @name $componentMapper#setComponentFromCtrlMapping
     * @description takes a function for mapping component controller names to component names
     */
    setComponentFromCtrlMapping: function (newFn) {
      ctrlToComponent = newFn;
      return this;
    },

    /**
     * @name $componentMapper#setTemplateMapping
     * @description takes a function for mapping component names to component template URLs
     */
    setTemplateMapping: function(newFn) {
      componentToTemplate = newFn;
      return this;
    }
  };
}

// this is a hack as a result of the build system used to transpile
function privatePipelineFactory($pipeline) {
  return $pipeline;
}

function dashCase(str) {
  return str.replace(/([A-Z])/g, function ($1) {
    return '-' + $1.toLowerCase();
  });
}
<|endoftext|>


<commit_before>// treeshake-header:start //
var define, internal, finalize = function () {
};
(function () {
    var get, defined, pending, definitions, initDefinition,
        $cachelyToken = '~',
        $depsRequiredByDefinitionToken = '.';

    /**
     * Sets and Gets cache, defined, and pending items in a private internal cache
     */
    get = Function[$cachelyToken] = Function[$cachelyToken] || function (name) {
            if (!get[name]) {
                get[name] = {};
            }
            return get[name];
        };

    definitions = get('c'); // these are items that have been initialized and permanently cached
    defined = get('d'); // these are items that have been defined but have not been initialized
    pending = get('p'); // these are items that have been initialized but have deps that need initialized before done

    /**
     * Initializes
     */
    initDefinition = function (name) {
        var args = arguments;
        var val = args[1];
        if (typeof val === 'function') {
            // ex. define('myFunc', function(){...});
            defined[name] = val(); // invoke immediately and assign to defined
        } else {
            // store in a temporary definitions until all definitions have been processed
            // ex. define('myFunc', ['toBoolean'], function(toBoolean){...})
            definitions[name] = args[2]; // skip array and assign funtion to cached name
            definitions[name][$depsRequiredByDefinitionToken] = val; // assign dependencies to definitions on function itself
        }
    };

    /**
     * define(); internal is deprecated
     */
    define = internal = function () {
        initDefinition.apply(null, arguments);
    };

    resolve = function (name, fn) {
        pending[name] = true; // mark this definition as pending
        var deps = fn[$depsRequiredByDefinitionToken]; // get any dependencies required by definition
        var args = [];
        var i, len;
        var dependencyName;
        if (deps) {
            len = deps.length;
            for (i = 0; i < len; i++) {
                dependencyName = deps[i];
                if (definitions[dependencyName]) {
                    if (pending.hasOwnProperty(dependencyName)) {
                        throw new Error('Cyclical reference: "' + name + '" referencing "' + dependencyName + '"');
                    }
                    resolve(dependencyName, definitions[dependencyName]);
                    delete definitions[dependencyName];
                }
            }
        }

        if (!defined.hasOwnProperty(name)) { // if the item has not been defined
            for (i = 0; i < len; i++) { // loop through dependencies
                dependencyName = deps[i]; // get the dependency name
                args.push(defined.hasOwnProperty(dependencyName) && defined[dependencyName]); // this will push an item even if it is undefined
            }
            defined[name] = fn.apply(null, args); // call the function and assign return value onto defined list
        }

        delete pending[name]; // permanently remove pending item
    };

    finalize = function () {
        for (var name in definitions) {
            resolve(name, definitions[name]);
        }
    };

    return define;
}());

//! ################# YOUR CODE STARTS HERE #################### //

// treeshake-header:end //
<commit_msg>treeshake get rid of cyclical reference error.<commit_after>// treeshake-header:start //
var define, internal, finalize = function () {
};
(function () {
    var get, defined, pending, definitions, initDefinition,
        $cachelyToken = '~',
        $depsRequiredByDefinitionToken = '.';

    /**
     * Sets and Gets cache, defined, and pending items in a private internal cache
     */
    get = Function[$cachelyToken] = Function[$cachelyToken] || function (name) {
            if (!get[name]) {
                get[name] = {};
            }
            return get[name];
        };

    definitions = get('c'); // these are items that have been initialized and permanently cached
    defined = get('d'); // these are items that have been defined but have not been initialized
    pending = get('p'); // these are items that have been initialized but have deps that need initialized before done

    /**
     * Initializes
     */
    initDefinition = function (name) {
        var args = arguments;
        var val = args[1];
        if (typeof val === 'function') {
            // ex. define('myFunc', function(){...});
            defined[name] = val(); // invoke immediately and assign to defined
        } else {
            // store in a temporary definitions until all definitions have been processed
            // ex. define('myFunc', ['toBoolean'], function(toBoolean){...})
            definitions[name] = args[2]; // skip array and assign funtion to cached name
            definitions[name][$depsRequiredByDefinitionToken] = val; // assign dependencies to definitions on function itself
        }
    };

    /**
     * define(); internal is deprecated
     */
    define = internal = function () {
        initDefinition.apply(null, arguments);
    };

    resolve = function (name, fn) {
        pending[name] = true; // mark this definition as pending
        var deps = fn[$depsRequiredByDefinitionToken]; // get any dependencies required by definition
        var args = [];
        var i, len;
        var dependencyName;
        if (deps) {
            len = deps.length;
            for (i = 0; i < len; i++) {
                dependencyName = deps[i];
                if (definitions[dependencyName]) {
                    if (!pending.hasOwnProperty(dependencyName)) {
                        resolve(dependencyName, definitions[dependencyName]);
                    }
                    resolve(dependencyName, definitions[dependencyName]);
                    delete definitions[dependencyName];
                }
            }
        }

        if (!defined.hasOwnProperty(name)) { // if the item has not been defined
            for (i = 0; i < len; i++) { // loop through dependencies
                dependencyName = deps[i]; // get the dependency name
                args.push(defined.hasOwnProperty(dependencyName) && defined[dependencyName]); // this will push an item even if it is undefined
            }
            defined[name] = fn.apply(null, args); // call the function and assign return value onto defined list
        }

        delete pending[name]; // permanently remove pending item
    };

    finalize = function () {
        for (var name in definitions) {
            resolve(name, definitions[name]);
        }
    };

    return define;
}());

//! ################# YOUR CODE STARTS HERE #################### //

// treeshake-header:end //
<|endoftext|>


<commit_before>var data;
var graph,graph2;

function loadData(d,attr){

	// Remove extra newlines at the end
	d = d.replace(/[\n\r]$/,"");

	data = CSV2JSON(d,[{'name':'unixdate','format':'number'},
								{'name':'date','format':'date'},
								{'name':'T','format':'number'},
								{'name':'L','format':'number'}
	]);

	processLoad();

	return this;
}

function processLoad(){

	var G = {};
	G.sum = function(a) { var i, sum; for (i = 0, sum = 0; i  0){

		var temp = [];
		var light = [];
		var smooth = new Array();
		var s1 = new Array();
		var s2 = new Array();

		// Assume all the gas and electric points have the same dates for the same rows (may not be true though
		for(var i = 0; i < data.length ; i++){
			if(data[i].date){
				s1.push({x:data[i].date,y:data[i].T,err:2,date:(data[i].date).toISOString()});
				s2.push({x:data[i].date,y:data[i].L,date:(data[i].date).toISOString()});
			}
		}
		var dx = 900*1000;
		var n = Math.round((data[data.length-1].date.getTime() - data[0].date.getTime())/dx);
		var sigma2 = Math.pow(3600,2);
		for(var i = 0; i < n ;i++){
			var d = new Date(Math.round(data[0].date.getTime()/dx)*dx + dx*i);
			var v = new Array();
			var weight = 0;
			var neg = false;
			var pos = false;
			for(var j = 0; j < data.length; j++){
				diff = (data[j].date - d)/1000;
				w = Math.exp(-(diff*diff)/sigma2);
				if(w > 0.1){
					if(diff < 0) neg = true;
					if(diff > 0) pos = true;
					weight += w;
					v.push(w * data[j].T);
				}
			}
			if(v.length > 0 && neg && pos) smooth.push({x:d, y: (G.sum(v)/weight).toFixed(1), date: d.toISOString() });
		}

		temp.push({
			// Data in the form [{x:x1,y:y1,err:err1},...{x:xn,y:yn,err:errn}]
			data: s1,
			color: '#D60303',
			points: { show: true, radius: 3, errors: 0.3 },
			lines: { show: false ,width: 1 },
			title: 'LoRaWAN mote',
			clickable: false,
			hoverable: true,
			// Modify the default hover text with replacements
			hover: {
				text: 'Temperature: {{y}}'+parseHTML('°')+'C
{{date}}',
				before: '{{title}}
'
			},
			css: {
			  'font-size': '0.8em',
			  'background-color': 'white',
			  'color': 'black',
			  'padding': '1em',
			  'border-radius': '0px'
			}
		});
		temp.push({
			// Data in the form [{x:x1,y:y1,err:err1},...{x:xn,y:yn,err:errn}]
			data: smooth,
			color: '#000000',
			points: { show: false, radius: 3 },
			lines: { show: true ,width: 1.5 },
			title: 'Smoothed average',
			clickable: false,
			hoverable: true,
			// Modify the default hover text with replacements
			hover: {
				text: 'Temperature: {{y}}'+parseHTML('°')+'C
{{date}}',
				before: '{{title}}
'
			},
			css: {
			  'font-size': '0.8em',
			  'background-color': 'white',
			  'color': 'black',
			  'padding': '1em',
			  'border-radius': '0px'
			}
		});

		if(graph){
			graph.updateData(temp);
		}else{
			S('#temperature').css({"width":"100%","height":"350px","margin-bottom":"16px"});
			graph = $.graph('temperature', temp, {
				xaxis: { 'label': 'Date/time', 'mode': 'time' },
				yaxis: { 'label': 'Temperature / '+parseHTML('°')+'C' },
				zoommode: "x",
				hoverable: true,
				grid: { hoverable: true, clickable: true, show: false, background: 'transparent', color: 'rgba(0,0,0,1)', colorZoom: 'rgba(214,3,3,0.2)' }
			});
		}

		light.push({
			data: s2,
			color: '#F9BC26',
			points: { show: true, radius: 3 },
			lines: { show: false ,width: 1 },
			title: 'LoRaWAN mote',
			clickable: false,
			hoverable: true,
			// Modify the default hover text with replacements
			hover: {
				text: 'Light: {{y}}
{{date}}',
				before: '{{title}}
'
			},
			css: {
			  'font-size': '0.8em',
			  'background-color': 'white',
			  'color': 'black',
			  'padding': '1em',
			  'border-radius': '0px'
			}
		})
		if(graph2){
			graph2.updateData(light);
		}else{
			S('#light').css({"width":"100%","height":"350px","margin-bottom":"16px"});
			graph2 = $.graph('light', light, {
				xaxis: { 'label': 'Date/time', 'mode': 'time' },
				yaxis: { 'label': 'Ambient light' },
				zoommode: "x",
				hoverable: true,
				grid: { hoverable: true, clickable: true, show: false, background: 'transparent', colorZoom: 'rgba(249,188,38,0.2)' }
			});
			// Tie the two graph's x-axes together
			graph.bind("mouseup",{me:graph,other:graph2},function(e){
				var g1 = e.data.me;
				var g2 = e.data.other;
				g2.defineAxis("x",g1.x.min,g1.x.max);
				g2.calculateData();
				g2.clear();
				g2.draw();
			});
			// Tie the two graph's x-axes together
			graph2.bind("mouseup",{me:graph2,other:graph},function(e){
				var g1 = e.data.me;
				var g2 = e.data.other;
				g2.defineAxis("x",g1.x.min,g1.x.max);
				g2.calculateData();
				g2.clear();
				g2.draw();
			});
			graph.trigger("mouseup")
		}
	}
}

// Return array of string values, or NULL if CSV string not well formed.
function CSVtoArray(text) {
	var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
	var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
	// Return NULL if input string is not well formed CSV string.
	if (!re_valid.test(text)) return null;
	var a = [];                     // Initialize array to receive values.
	text.replace(re_value, // "Walk" the string using replace with callback.
		function(m0, m1, m2, m3) {
			// Remove backslash from \' in single quoted values.
			if      (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
			// Remove backslash from \" in double quoted values.
			else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
			else if (m3 !== undefined) a.push(m3);
			return ''; // Return empty string.
		});
	// Handle special case of empty last value.
	if (/,\s*$/.test(text)) a.push('');
	return a;
};

function CSV2JSON(data,format,start,end){

	if(typeof start!=="number") start = 1;
	var delim = ",";

	if(typeof data==="string"){
		data = data.replace(/\r/,'');
		data = data.split(/[\n]/);
	}
	if(typeof end!=="number") end = data.length;

	if(data[0].indexOf("\t") > 0) delim = /\t/;

	var line,datum;
	var newdata = new Array();
	for(var i = start; i < end; i++){
		line = CSVtoArray(data[i]);
		datum = {};
		if(line){
			for(var j=0; j < line.length; j++){
				if(format[j]){
					if(format[j].format=="number"){
						if(line[j]!=""){
							if(line[j]=="infinity" || line[j]=="Inf") datum[format[j].name] = Number.POSITIVE_INFINITY;
							else datum[format[j].name] = parseFloat(line[j]);
						}
					}else if(format[j].format=="eval"){
						if(line[j]!="") datum[format[j].name] = eval(line[j]);
					}else if(format[j].format=="date"){
						if(line[j]) datum[format[j].name] = new Date(line[j].replace(/^"/,"").replace(/"$/,""));
						else datum[format[j].name] = null;
					}else if(format[j].format=="boolean"){
						if(line[j]=="1" || line[j]=="true" || line[j]=="Y") datum[format[j].name] = true;
						else if(line[j]=="0" || line[j]=="false" || line[j]=="N") datum[format[j].name] = false;
						else datum[format[j].name] = null;
					}else{
						datum[format[j].name] = (line[j][0]=='"' && line[j][line[j].length-1]=='"') ? line[j].substring(1,line[j].length-1) : line[j];
					}
				}else{
					datum[j] = (line[j][0]=='"' && line[j][line[j].length-1]=='"') ? line[j].substring(1,line[j].length-1) : line[j];
				}
			}
			newdata.push(datum);
		}
	}
	return newdata;
}

function parseHTML(txt){
	var div = document.createElement("div");
	div.innerHTML = txt;
	return div.innerHTML;
}

S(document).ready(function(){

	function getData(){
		S().ajax('data.csv',{'complete':loadData,'this':this,'cache':false,'error':function(e){ console.log('error',e) }});
	}

	// Update every 5 minutes
	var intervalID = window.setInterval(getData, 300000);
	getData();

});

<commit_msg>Add units<commit_after>var data;
var graph,graph2;

function loadData(d,attr){

	// Remove extra newlines at the end
	d = d.replace(/[\n\r]$/,"");

	data = CSV2JSON(d,[{'name':'unixdate','format':'number'},
								{'name':'date','format':'date'},
								{'name':'T','format':'number'},
								{'name':'L','format':'number'}
	]);

	processLoad();

	return this;
}

function processLoad(){

	var G = {};
	G.sum = function(a) { var i, sum; for (i = 0, sum = 0; i  0){

		var temp = [];
		var light = [];
		var smooth = new Array();
		var s1 = new Array();
		var s2 = new Array();

		// Assume all the gas and electric points have the same dates for the same rows (may not be true though
		for(var i = 0; i < data.length ; i++){
			if(data[i].date){
				s1.push({x:data[i].date,y:data[i].T,err:2,date:(data[i].date).toISOString()});
				s2.push({x:data[i].date,y:data[i].L,date:(data[i].date).toISOString()});
			}
		}
		var dx = 900*1000;
		var n = Math.round((data[data.length-1].date.getTime() - data[0].date.getTime())/dx);
		var sigma2 = Math.pow(3600,2);
		for(var i = 0; i < n ;i++){
			var d = new Date(Math.round(data[0].date.getTime()/dx)*dx + dx*i);
			var v = new Array();
			var weight = 0;
			var neg = false;
			var pos = false;
			for(var j = 0; j < data.length; j++){
				diff = (data[j].date - d)/1000;
				w = Math.exp(-(diff*diff)/sigma2);
				if(w > 0.1){
					if(diff < 0) neg = true;
					if(diff > 0) pos = true;
					weight += w;
					v.push(w * data[j].T);
				}
			}
			if(v.length > 0 && neg && pos) smooth.push({x:d, y: (G.sum(v)/weight).toFixed(1), date: d.toISOString() });
		}

		temp.push({
			// Data in the form [{x:x1,y:y1,err:err1},...{x:xn,y:yn,err:errn}]
			data: s1,
			color: '#D60303',
			points: { show: true, radius: 3, errors: 0.3 },
			lines: { show: false ,width: 1 },
			title: 'LoRaWAN mote',
			clickable: false,
			hoverable: true,
			// Modify the default hover text with replacements
			hover: {
				text: 'Temperature: {{y}}'+parseHTML('°')+'C
{{date}}',
				before: '{{title}}
'
			},
			css: {
			  'font-size': '0.8em',
			  'background-color': 'white',
			  'color': 'black',
			  'padding': '1em',
			  'border-radius': '0px'
			}
		});
		temp.push({
			// Data in the form [{x:x1,y:y1,err:err1},...{x:xn,y:yn,err:errn}]
			data: smooth,
			color: '#000000',
			points: { show: false, radius: 3 },
			lines: { show: true ,width: 1.5 },
			title: 'Smoothed average',
			clickable: false,
			hoverable: true,
			// Modify the default hover text with replacements
			hover: {
				text: 'Temperature: {{y}}'+parseHTML('°')+'C
{{date}}',
				before: '{{title}}
'
			},
			css: {
			  'font-size': '0.8em',
			  'background-color': 'white',
			  'color': 'black',
			  'padding': '1em',
			  'border-radius': '0px'
			}
		});

		if(graph){
			graph.updateData(temp);
		}else{
			S('#temperature').css({"width":"100%","height":"350px","margin-bottom":"16px"});
			graph = $.graph('temperature', temp, {
				xaxis: { 'label': 'Date/time', 'mode': 'time' },
				yaxis: { 'label': 'Temperature / '+parseHTML('°')+'C' },
				zoommode: "x",
				hoverable: true,
				grid: { hoverable: true, clickable: true, show: false, background: 'transparent', color: 'rgba(0,0,0,1)', colorZoom: 'rgba(214,3,3,0.2)' }
			});
		}

		light.push({
			data: s2,
			color: '#F9BC26',
			points: { show: true, radius: 3 },
			lines: { show: false ,width: 1 },
			title: 'LoRaWAN mote',
			clickable: false,
			hoverable: true,
			// Modify the default hover text with replacements
			hover: {
				text: 'Light: {{y}}
{{date}}',
				before: '{{title}}
'
			},
			css: {
			  'font-size': '0.8em',
			  'background-color': 'white',
			  'color': 'black',
			  'padding': '1em',
			  'border-radius': '0px'
			}
		})
		if(graph2){
			graph2.updateData(light);
		}else{
			S('#light').css({"width":"100%","height":"350px","margin-bottom":"16px"});
			graph2 = $.graph('light', light, {
				xaxis: { 'label': 'Date/time', 'mode': 'time' },
				yaxis: { 'label': 'Ambient light (lx)' },
				zoommode: "x",
				hoverable: true,
				grid: { hoverable: true, clickable: true, show: false, background: 'transparent', colorZoom: 'rgba(249,188,38,0.2)' }
			});
			// Tie the two graph's x-axes together
			graph.bind("mouseup",{me:graph,other:graph2},function(e){
				var g1 = e.data.me;
				var g2 = e.data.other;
				g2.defineAxis("x",g1.x.min,g1.x.max);
				g2.calculateData();
				g2.clear();
				g2.draw();
			});
			// Tie the two graph's x-axes together
			graph2.bind("mouseup",{me:graph2,other:graph},function(e){
				var g1 = e.data.me;
				var g2 = e.data.other;
				g2.defineAxis("x",g1.x.min,g1.x.max);
				g2.calculateData();
				g2.clear();
				g2.draw();
			});
			graph.trigger("mouseup")
		}
	}
}

// Return array of string values, or NULL if CSV string not well formed.
function CSVtoArray(text) {
	var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
	var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
	// Return NULL if input string is not well formed CSV string.
	if (!re_valid.test(text)) return null;
	var a = [];                     // Initialize array to receive values.
	text.replace(re_value, // "Walk" the string using replace with callback.
		function(m0, m1, m2, m3) {
			// Remove backslash from \' in single quoted values.
			if      (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
			// Remove backslash from \" in double quoted values.
			else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
			else if (m3 !== undefined) a.push(m3);
			return ''; // Return empty string.
		});
	// Handle special case of empty last value.
	if (/,\s*$/.test(text)) a.push('');
	return a;
};

function CSV2JSON(data,format,start,end){

	if(typeof start!=="number") start = 1;
	var delim = ",";

	if(typeof data==="string"){
		data = data.replace(/\r/,'');
		data = data.split(/[\n]/);
	}
	if(typeof end!=="number") end = data.length;

	if(data[0].indexOf("\t") > 0) delim = /\t/;

	var line,datum;
	var newdata = new Array();
	for(var i = start; i < end; i++){
		line = CSVtoArray(data[i]);
		datum = {};
		if(line){
			for(var j=0; j < line.length; j++){
				if(format[j]){
					if(format[j].format=="number"){
						if(line[j]!=""){
							if(line[j]=="infinity" || line[j]=="Inf") datum[format[j].name] = Number.POSITIVE_INFINITY;
							else datum[format[j].name] = parseFloat(line[j]);
						}
					}else if(format[j].format=="eval"){
						if(line[j]!="") datum[format[j].name] = eval(line[j]);
					}else if(format[j].format=="date"){
						if(line[j]) datum[format[j].name] = new Date(line[j].replace(/^"/,"").replace(/"$/,""));
						else datum[format[j].name] = null;
					}else if(format[j].format=="boolean"){
						if(line[j]=="1" || line[j]=="true" || line[j]=="Y") datum[format[j].name] = true;
						else if(line[j]=="0" || line[j]=="false" || line[j]=="N") datum[format[j].name] = false;
						else datum[format[j].name] = null;
					}else{
						datum[format[j].name] = (line[j][0]=='"' && line[j][line[j].length-1]=='"') ? line[j].substring(1,line[j].length-1) : line[j];
					}
				}else{
					datum[j] = (line[j][0]=='"' && line[j][line[j].length-1]=='"') ? line[j].substring(1,line[j].length-1) : line[j];
				}
			}
			newdata.push(datum);
		}
	}
	return newdata;
}

function parseHTML(txt){
	var div = document.createElement("div");
	div.innerHTML = txt;
	return div.innerHTML;
}

S(document).ready(function(){

	function getData(){
		S().ajax('data.csv',{'complete':loadData,'this':this,'cache':false,'error':function(e){ console.log('error',e) }});
	}

	// Update every 5 minutes
	var intervalID = window.setInterval(getData, 300000);
	getData();

});

<|endoftext|>


<commit_before>'use strict';
/**
 * @file
 * Suggest Transformers
 *
 * The file contains several transformer functions:
 *
 *  * creatorSuggestTransformer
 *    Returns creator suggestions based on query
 *  * librarySuggestTransformer
 *    Returns library suggestions based on query
 *  * subjectSuggestTransformer
 *    Returns subject suggestions based on query
 *  * popSuggestTransformer
 *    Returns solr documents sorted according to loan count
 *  * suggestTransformer
 *    Transformer bsaed on the above mentioned transformers.
 *    The suggestTransformer supports 4 types of suggestions:
 *    creator, library, subject and title
 */

import {clone} from 'lodash';
import genericTransformer from '../genericTransformer.js';
import entitySuggest from '../services/EntitySuggest/neoClient.js';
import popSuggest from '../services/PopSuggest/client.js';
import utils from '../utils.js';

/**
* Helper function to change key name in an object
*/
function changeKey(obj, fromKey, toKey) {
  if (obj.hasOwnProperty(fromKey)) {
    obj[toKey] = obj[fromKey];
    delete obj[fromKey];
  }
  return obj;
}

/**
* Transformer for subjectSuggest endpoint.
* This transformer calls the entitySuggest client and returns subject
* suggestions
*/
export function subjectSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function subjectSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function subjectSuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'entityEndpoint', 'endpoint');
  let client = entitySuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getSubjectSuggestions(request), state: state};
  };
}

export function subjectSuggestTransformer() {
  return genericTransformer(subjectSuggestRequest,
                            subjectSuggestResponse,
                            subjectSuggestFunction);
}

/**
* Transformer for creatorSuggest endpoint.
* This transformer calls the entitySuggest client and returns creator
* suggestions
*/

export function creatorSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function creatorSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function creatorSuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'entityEndpoint', 'endpoint');
  let client = entitySuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getCreatorSuggestions(request), state: state};
  };
}

export function creatorSuggestTransformer() {
  return genericTransformer(creatorSuggestRequest,
                            creatorSuggestResponse,
                            creatorSuggestFunction);
}

/**
* Transformer for librarySuggest endpoint.
* This transformer calls the entitySuggest client and returns library
* suggestions
*/
export function librarySuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function librarySuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.response.suggestions.map((obj) => {
    obj.suggestion.str = obj.suggestion.navn + ', ' + obj.suggestion.by;
    return obj.suggestion;
  })};
}

export function librarySuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'entityEndpoint', 'endpoint');
  let client = entitySuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getLibrarySuggestions(request), state: state};
  };
}

export function librarySuggestTransformer() {
  return genericTransformer(librarySuggestRequest,
                            librarySuggestResponse,
                            librarySuggestFunction);
}

/**
* Transformer for popSuggest endpoint.
* This transformer calls the popSuggestion client and returns solr
* document suggestions
*/
export function popSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, rows: request.limit, fields: request.fields};
  return {transformedRequest: clientRequest, state: state};
}

export function popSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response};
}

export function popSuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'popEndpoint', 'endpoint');
  let client = popSuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getPopSuggestions(request), state: state};
  };
}

export function popSuggestTransformer() {
  return genericTransformer(popSuggestRequest,
                            popSuggestResponse,
                            popSuggestFunction);
}

/**
* Transformer for suggest endpoint.
*
* This transformer calls the appropriate suggesttransformer based on
* the type parameter in the request, and returns the fetched
* suggestions.
*
* Available types are: creator, library, subject and title
*/

export function suggestRequest(request, context, state) { // eslint-disable-line no-unused-vars

  state.type = request.type;
  let requestEnvelope = {type: request.type,
                         request: {q: request.q,
                                   limit: request.limit}};

  if (requestEnvelope.type === 'title') {
    requestEnvelope.request.fields = 'display.title,fedoraPid,display.creator,display.workType';
    requestEnvelope.request.q = 'display.title:{!complexphrase inOrder=true}' + requestEnvelope.request.q;
  }
  return {transformedRequest: requestEnvelope, state: state};
}

export function suggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  let statusCode = response.statusCode;
  if (state.type === 'title') {
    response = response.data.response.docs.map((obj) => {
      let retObj = {str: obj['display.title'][0], id: obj.fedoraPid};
      if (obj.hasOwnProperty('display.creator')) {
        retObj.creator = obj['display.creator'][0];
      }
      if (obj.hasOwnProperty('display.workType')) {
        retObj.type = obj['display.workType'][0];
      }
      return retObj;
    });
  }
  return {statusCode: statusCode, data: response.data};
}

export function suggestFunction(context) {

  let transformers = {subject: subjectSuggestTransformer(),
                      creator: creatorSuggestTransformer(),
                      library: librarySuggestTransformer(),
                      title: popSuggestTransformer()};

  return (requestEnvelope, localContext, state) => { // eslint-disable-line no-unused-vars
    if (!transformers.hasOwnProperty(requestEnvelope.type)) {
      utils.die('SuggestFunction "' + requestEnvelope.type + '" is unknown');
    }

    return {response: transformers[requestEnvelope.type](requestEnvelope.request, context),
            state: state};
  };
}

export function suggestTransformer() {

  return genericTransformer(suggestRequest,
                            suggestResponse,
                            suggestFunction);
}
<commit_msg>removed whitespace<commit_after>'use strict';
/**
 * @file
 * Suggest Transformers
 *
 * The file contains several transformer functions:
 *
 *  * creatorSuggestTransformer
 *    Returns creator suggestions based on query
 *  * librarySuggestTransformer
 *    Returns library suggestions based on query
 *  * subjectSuggestTransformer
 *    Returns subject suggestions based on query
 *  * popSuggestTransformer
 *    Returns solr documents sorted according to loan count
 *  * suggestTransformer
 *    Transformer bsaed on the above mentioned transformers.
 *    The suggestTransformer supports 4 types of suggestions:
 *    creator, library, subject and title
 */

import {clone} from 'lodash';
import genericTransformer from '../genericTransformer.js';
import entitySuggest from '../services/EntitySuggest/neoClient.js';
import popSuggest from '../services/PopSuggest/client.js';
import utils from '../utils.js';

/**
* Helper function to change key name in an object
*/
function changeKey(obj, fromKey, toKey) {
  if (obj.hasOwnProperty(fromKey)) {
    obj[toKey] = obj[fromKey];
    delete obj[fromKey];
  }
  return obj;
}

/**
* Transformer for subjectSuggest endpoint.
* This transformer calls the entitySuggest client and returns subject
* suggestions
*/
export function subjectSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function subjectSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function subjectSuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'entityEndpoint', 'endpoint');
  let client = entitySuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getSubjectSuggestions(request), state: state};
  };
}

export function subjectSuggestTransformer() {
  return genericTransformer(subjectSuggestRequest,
                            subjectSuggestResponse,
                            subjectSuggestFunction);
}

/**
* Transformer for creatorSuggest endpoint.
* This transformer calls the entitySuggest client and returns creator
* suggestions
*/

export function creatorSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function creatorSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function creatorSuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'entityEndpoint', 'endpoint');
  let client = entitySuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getCreatorSuggestions(request), state: state};
  };
}

export function creatorSuggestTransformer() {
  return genericTransformer(creatorSuggestRequest,
                            creatorSuggestResponse,
                            creatorSuggestFunction);
}

/**
* Transformer for librarySuggest endpoint.
* This transformer calls the entitySuggest client and returns library
* suggestions
*/
export function librarySuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function librarySuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.response.suggestions.map((obj) => {
    obj.suggestion.str = obj.suggestion.navn + ', ' + obj.suggestion.by;
    return obj.suggestion;
  })};
}

export function librarySuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'entityEndpoint', 'endpoint');
  let client = entitySuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getLibrarySuggestions(request), state: state};
  };
}

export function librarySuggestTransformer() {
  return genericTransformer(librarySuggestRequest,
                            librarySuggestResponse,
                            librarySuggestFunction);
}

/**
* Transformer for popSuggest endpoint.
* This transformer calls the popSuggestion client and returns solr
* document suggestions
*/
export function popSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, rows: request.limit, fields: request.fields};
  return {transformedRequest: clientRequest, state: state};
}

export function popSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response};
}

export function popSuggestFunction(context) {
  let contextCopy = clone(context);
  changeKey(contextCopy, 'popEndpoint', 'endpoint');
  let client = popSuggest(contextCopy);
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: client.getPopSuggestions(request), state: state};
  };
}

export function popSuggestTransformer() {
  return genericTransformer(popSuggestRequest,
                            popSuggestResponse,
                            popSuggestFunction);
}

/**
* Transformer for suggest endpoint.
*
* This transformer calls the appropriate suggesttransformer based on
* the type parameter in the request, and returns the fetched
* suggestions.
*
* Available types are: creator, library, subject and title
*/

export function suggestRequest(request, context, state) { // eslint-disable-line no-unused-vars

  state.type = request.type;
  let requestEnvelope = {type: request.type,
                         request: {q: request.q,
                                   limit: request.limit}};

  if (requestEnvelope.type === 'title') {
    requestEnvelope.request.fields = 'display.title,fedoraPid,display.creator,display.workType';
    requestEnvelope.request.q = 'display.title:{!complexphrase inOrder=true}' + requestEnvelope.request.q;
  }
  return {transformedRequest: requestEnvelope, state: state};
}

export function suggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  let statusCode = response.statusCode;
  if (state.type === 'title') {
    response = response.data.response.docs.map((obj) => {
      let retObj = {str: obj['display.title'][0], id: obj.fedoraPid};
      if (obj.hasOwnProperty('display.creator')) {
        retObj.creator = obj['display.creator'][0];
      }
      if (obj.hasOwnProperty('display.workType')) {
        retObj.type = obj['display.workType'][0];
      }
      return retObj;
    });
  }
  return {statusCode: statusCode, data: response.data};
}

export function suggestFunction(context) {

  let transformers = {subject: subjectSuggestTransformer(),
                      creator: creatorSuggestTransformer(),
                      library: librarySuggestTransformer(),
                      title: popSuggestTransformer()};

  return (requestEnvelope, localContext, state) => { // eslint-disable-line no-unused-vars
    if (!transformers.hasOwnProperty(requestEnvelope.type)) {
      utils.die('SuggestFunction "' + requestEnvelope.type + '" is unknown');
    }

    return {response: transformers[requestEnvelope.type](requestEnvelope.request, context),
            state: state};
  };
}

export function suggestTransformer() {

  return genericTransformer(suggestRequest,
                            suggestResponse,
                            suggestFunction);
}
<|endoftext|>


<commit_before>'use strict';
/**
 * @file
 * Suggest Transformers
 *
 * The file contains several transformer functions:
 *
 *  * creatorSuggestTransformer
 *    Returns creator suggestions based on query
 *  * librarySuggestTransformer
 *    Returns library suggestions based on query
 *  * subjectSuggestTransformer
 *    Returns subject suggestions based on query
 *  * popsuggestTransformer
 *    Returns solr documents sorted according to loan count
 *  * suggestTransformer
 *    Transformer bsaed on the above mentioned transformers.
 *    The suggestTransformer supports 4 types of suggestions:
 *    creator, library, subject and title
 */
import genericTransformer from '../genericTransformer.js';
import {die} from '../utils.js';
import {sendRequest} from '../services/HTTPClient.js';

/**
* Transformer for subjectSuggest endpoint.
* This transformer calls the entitysuggest client and returns subject
* suggestions
*/
export function subjectSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function subjectSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function subjectSuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    request.lt = context.data.entitysuggest.libraryType;
    let url = context.data.entitysuggest.url + '/' + 'subject';
    return {response: sendRequest(url, request), state: state};
  };
}

export function subjectSuggestTransformer() {
  return genericTransformer(subjectSuggestRequest,
                            subjectSuggestResponse,
                            subjectSuggestFunction);
}

/**
* Transformer for creatorSuggest endpoint.
* This transformer calls the entitysuggest client and returns creator
* suggestions
*/
export function creatorSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function creatorSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function creatorSuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    request.lt = context.data.entitysuggest.libraryType;
    let url = context.data.entitysuggest.url + '/' + 'creator';
    return {response: sendRequest(url, request), state: state};
  };
}

export function creatorSuggestTransformer() {
  return genericTransformer(creatorSuggestRequest,
                            creatorSuggestResponse,
                            creatorSuggestFunction);
}

/**
* Transformer for librarySuggest endpoint.
* This transformer calls the entitysuggest client and returns library
* suggestions
*/
export function librarySuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function librarySuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data.response.suggestions.map((obj) => {
    obj.suggestion.str = obj.suggestion.navn + ', ' + obj.suggestion.by;
    return obj.suggestion;
  })};
}

export function librarySuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    request.lt = context.data.entitysuggest.libraryType;
    let url = context.data.entitysuggest.url + '/' + 'library';
    return {response: sendRequest(url, request), state: state};
  };
}

export function librarySuggestTransformer() {
  return genericTransformer(librarySuggestRequest,
                            librarySuggestResponse,
                            librarySuggestFunction);
}

/**
* Transformer for popsuggest endpoint.
* This transformer calls the popsuggestion client and returns solr
* document suggestions
*/
export function popSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, rows: request.limit, fields: request.fields};
  return {transformedRequest: clientRequest, state: state};
}

export function popSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data};
}

export function popSuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: sendRequest(context.data.popsuggest.url, request), state: state};
  };
}

export function popSuggestTransformer() {
  return genericTransformer(popSuggestRequest,
                            popSuggestResponse,
                            popSuggestFunction);
}

/**
* Transformer for suggest endpoint.
*
* This transformer calls the appropriate suggesttransformer based on
* the type parameter in the request, and returns the fetched
* suggestions.
*
* Available types are: creator, library, subject and title
*/

export function suggestRequest(request, context, state) { // eslint-disable-line no-unused-vars

  state.type = request.type;
  let requestEnvelope = {type: request.type,
                         request: {q: request.q,
                                   limit: request.limit}};

  if (requestEnvelope.type === 'title') {
    requestEnvelope.request.fields = 'display.title,fedoraPid,display.creator,display.workType';
    requestEnvelope.request.q = 'display.title:{!complexphrase inOrder=true}' + requestEnvelope.request.q;
  }
  return {transformedRequest: requestEnvelope, state: state};
}

function mapTitleKeys(obj) {
  let retObj = {str: obj['display.title'][0], id: obj.fedoraPid};
  if (obj.hasOwnProperty('display.creator')) {
    retObj.creator = obj['display.creator'][0];
  }
  if (obj.hasOwnProperty('display.workType')) {
    retObj.type = obj['display.workType'][0];
  }
  return retObj;
}

export function suggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  let statusCode = response.statusCode;
  if (state.type === 'title') {
    response.data = response.data.response.docs.map((obj) => {
      return mapTitleKeys(obj);
    });
  }
  return {statusCode: statusCode, data: response.data};
}

export function suggestFunction(context) {

  let transformers = {subject: subjectSuggestTransformer(),
                      creator: creatorSuggestTransformer(),
                      library: librarySuggestTransformer(),
                      title: popSuggestTransformer()};

  return (requestEnvelope, localContext, state) => { // eslint-disable-line no-unused-vars
    if (!transformers.hasOwnProperty(requestEnvelope.type)) {
      die('SuggestFunction "' + requestEnvelope.type + '" is unknown');
    }

    return {response: transformers[requestEnvelope.type](requestEnvelope.request, context),
            state: state};
  };
}

export function suggestTransformer() {

  return genericTransformer(suggestRequest,
                            suggestResponse,
                            suggestFunction);
}
<commit_msg>use context.call etc., fixes #192<commit_after>'use strict';
/**
 * @file
 * Suggest Transformers
 *
 * The file contains several transformer functions:
 *
 *  * creatorSuggestTransformer
 *    Returns creator suggestions based on query
 *  * librarySuggestTransformer
 *    Returns library suggestions based on query
 *  * subjectSuggestTransformer
 *    Returns subject suggestions based on query
 *  * popsuggestTransformer
 *    Returns solr documents sorted according to loan count
 *  * suggestTransformer
 *    Transformer bsaed on the above mentioned transformers.
 *    The suggestTransformer supports 4 types of suggestions:
 *    creator, library, subject and title
 */
import genericTransformer from '../genericTransformer.js';
import {die} from '../utils.js';

/**
* Transformer for subjectSuggest endpoint.
* This transformer calls the entitysuggest client and returns subject
* suggestions
*/
export function subjectSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function subjectSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function subjectSuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    request.lt = context.data.entitysuggest.libraryType;
    let url = context.data.entitysuggest.url + '/' + 'subject';
    return {response: context.call(url, request), state: state};
  };
}

export function subjectSuggestTransformer() {
  return genericTransformer(subjectSuggestRequest,
                            subjectSuggestResponse,
                            subjectSuggestFunction);
}

/**
* Transformer for creatorSuggest endpoint.
* This transformer calls the entitysuggest client and returns creator
* suggestions
*/
export function creatorSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function creatorSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data.response.suggestions.map((obj) => {
    return {str: obj.suggestion};
  })};
}

export function creatorSuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    request.lt = context.data.entitysuggest.libraryType;
    let url = context.data.entitysuggest.url + '/' + 'creator';
    return {response: context.call(url, request), state: state};
  };
}

export function creatorSuggestTransformer() {
  return genericTransformer(creatorSuggestRequest,
                            creatorSuggestResponse,
                            creatorSuggestFunction);
}

/**
* Transformer for librarySuggest endpoint.
* This transformer calls the entitysuggest client and returns library
* suggestions
*/
export function librarySuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, n: request.limit};
  return {transformedRequest: clientRequest, state: state};
}

export function librarySuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data.response.suggestions.map((obj) => {
    obj.suggestion.str = obj.suggestion.navn + ', ' + obj.suggestion.by;
    return obj.suggestion;
  })};
}

export function librarySuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    request.lt = context.data.entitysuggest.libraryType;
    let url = context.data.entitysuggest.url + '/' + 'library';
    return {response: context.call(url, request), state: state};
  };
}

export function librarySuggestTransformer() {
  return genericTransformer(librarySuggestRequest,
                            librarySuggestResponse,
                            librarySuggestFunction);
}

/**
* Transformer for popsuggest endpoint.
* This transformer calls the popsuggestion client and returns solr
* document suggestions
*/
export function popSuggestRequest(request, context, state) { // eslint-disable-line no-unused-vars
  let clientRequest = {query: request.q, rows: request.limit, fields: request.fields};
  return {transformedRequest: clientRequest, state: state};
}

export function popSuggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  return {statusCode: 200, data: response.data};
}

export function popSuggestFunction(context) {
  return (request, localContext, state) => { // eslint-disable-line no-unused-vars
    return {response: context.call(context.data.popsuggest.url, request), state: state};
  };
}

export function popSuggestTransformer() {
  return genericTransformer(popSuggestRequest,
                            popSuggestResponse,
                            popSuggestFunction);
}

/**
* Transformer for suggest endpoint.
*
* This transformer calls the appropriate suggesttransformer based on
* the type parameter in the request, and returns the fetched
* suggestions.
*
* Available types are: creator, library, subject and title
*/

export function suggestRequest(request, context, state) { // eslint-disable-line no-unused-vars

  state.type = request.type;
  let requestEnvelope = {type: request.type,
                         request: {q: request.q,
                                   limit: request.limit}};

  if (requestEnvelope.type === 'title') {
    requestEnvelope.request.fields = 'display.title,fedoraPid,display.creator,display.workType';
    requestEnvelope.request.q = 'display.title:{!complexphrase inOrder=true}' + requestEnvelope.request.q;
  }
  return {transformedRequest: requestEnvelope, state: state};
}

function mapTitleKeys(obj) {
  let retObj = {str: obj['display.title'][0], id: obj.fedoraPid};
  if (obj.hasOwnProperty('display.creator')) {
    retObj.creator = obj['display.creator'][0];
  }
  if (obj.hasOwnProperty('display.workType')) {
    retObj.type = obj['display.workType'][0];
  }
  return retObj;
}

export function suggestResponse(response, context, state) { // eslint-disable-line no-unused-vars
  let statusCode = response.statusCode;
  if (state.type === 'title') {
    response.data = response.data.response.docs.map((obj) => {
      return mapTitleKeys(obj);
    });
  }
  return {statusCode: statusCode, data: response.data};
}

export function suggestFunction(context) {

  let transformers = {subject: subjectSuggestTransformer(),
                      creator: creatorSuggestTransformer(),
                      library: librarySuggestTransformer(),
                      title: popSuggestTransformer()};

  return (requestEnvelope, localContext, state) => { // eslint-disable-line no-unused-vars
    if (!transformers.hasOwnProperty(requestEnvelope.type)) {
      die('SuggestFunction "' + requestEnvelope.type + '" is unknown');
    }

    return {response: transformers[requestEnvelope.type](requestEnvelope.request, context),
            state: state};
  };
}

export function suggestTransformer() {

  return genericTransformer(suggestRequest,
                            suggestResponse,
                            suggestFunction);
}
<|endoftext|>


<commit_before>var annosource;

(function($){
	var inputs = {};

	annoSource = {
		init : function() {
			var t = this;
			t.widgets = [];
			inputs.$dialog = $('#anno-popup-source');
			inputs.$validate = $('#anno-source-validate');
			inputs.$insert = $('#anno-source-insert');
			inputs.$close = $('#anno-source-close');
			inputs.$all = $('.js-source-button');
			t.validationStatusID = '#validation-status';

			t.validator = window.annoValidation;

			inputs.$dialog.bind('wpdialogclose', annoSource.onClose);

			t.codemirror = CodeMirror.fromTextArea(document.getElementById('htmlSource'), {
				lineNumbers: true,
			});

			// Prevents CodeMirror from bugging out during show/hide/resize process
			$('body').on('click', '.mce_annosource', function(e) {
				e.preventDefault();
				t.codemirror.refresh();
			});

			// Re-evaluate the current xml
			inputs.$validate.on('click', function(e) {
				e.preventDefault();
				inputs.$all.prop('disabled', true);
				$(document).on('annoValidation', t.processValidation);
				t.validate().then(function(){
					inputs.$all.prop('disabled', false);
				});
			});

			// Insert the current XML back into the dom
			inputs.$insert.on('click', function(e) {
				e.preventDefault();
				$(document).on('annoValidation', t.processValidation);
				$(document).on('annoValidation', t.insertAlert);
				inputs.$all.prop('disabled', true);
				t.validate().then(function(){
					inputs.$all.prop('disabled', false);
				});
			});

			// Close the xml editor without inserting content
			inputs.$close.on('click', function(e) {
				e.preventDefault();
				t.close();
			});

			$('body').on('click', t.validationStatusID + ' a, .cm-error', function(e) {
				e.preventDefault();
				t.codemirror.focus();
				t.codemirror.setCursor($(this).data('line'), $(this).data('col'));
			});

			inputs.$dialog.bind('wpdialogbeforeopen', annoSource.beforeOpen);
		},
		validate : function(content) {
			var contentType;
			if (!content) {
				var content = this._getContent();
			}
			this._cleanup();
			contentType = this._getContentType();
			// Returns a promise
			return this.validator.validate(content, contentType);
		},
		insertContent : function() {
			this.editor.setContent('<!DOCTYPE sec SYSTEM "http://dtd.nlm.nih.gov/publishing/3.0/journalpublishing3.dtd">' + this.codemirror.getValue().trim() + '', {source_view : true});
			// Slightly hacky, but Textorum needs the content to be wrapped by a single element
			// Remove it after insertion.
			jQuery(this.editor.dom.select('div.body')[0].firstChild).unwrap();
		},
		close : function() {
			var ed = top.tinymce.activeEditor;
			ed.windowManager.close();
			ed.focus();
		},
		// * Internal Helper Functions ***************
		_getContentType : function () {
			var contentType = '';
			if (!this.editor) {
				this.editor = top.tinymce.activeEditor;
			}

			if (this.editor.id == 'content') {
				contentType = 'body';
			}
			else if (this.editor.id == 'excerpt') {
				contentType = 'abstract';
			}

			return contentType;
		},
		_cleanup : function() {
			$(this.validationStatusID).html('');
		},
		_getContent : function() {
			return this.codemirror.getValue();
		},
		// * Event Callbacks ***************
		processValidation : function(e, data) {
			var t = annoSource, widget, errors = data.errors, insertEl, msg, $statusUL = $(t.validationStatusID);
			$(document).off('annoValidation', t.processValidation);
			if (data.status == 'error' || data.status == 'fatal') {
				for (var i = 0; i <= errors.length - 1; i++) {
					// Insert error at top of editor
					insertEl = document.createElement('a');
					$(insertEl).text(errors[i].fullMessage).data('col', errors[i].column).data('line', errors[i].line).attr('href', '#');
					$statusUL.append($(insertEl).wrap('

').parent());
				};
			}
			else if (data.status == 'success') {
				insertEl = document.createElement('li');
				$(insertEl).text(data.message);
				$statusUL.append($(insertEl));
			}
		},
		insertAlert : function(e, data) {
			var t = annoSource, status = data.status;
			$(document).off('annoValidation', t.insertAlert);
			if (status == 'error') {
				if (confirm('There are validation errors still. Are you sure you want to insert this content?')) { //@TODO i18n
					// onClose triggers cleanup
					t.insertContent();
					t.close();
				}
			}
			else if (status == 'fatal') {
				alert('The structure of the XML is broken. Please fix this and try again');
			}
			else {
				// onClose triggers cleanup
				t.insertContent();
				t.close();
			}
		},
		beforeOpen : function () {
			var t = annoSource;
			var contentType = t._getContentType();

			t.editor = top.tinymce.activeEditor;
			t.editorVal = t.editor.getContent({source_view : true}).replace(/^<!DOCTYPE[^>]*?>/, '');
			t.codemirror.setValue(t.editorVal);
			$(document).on('annoValidation', t.processValidation);
			t.validate(t.editorVal, contentType);
		},
		onClose : function () {
			var t = annoSource;
			t._cleanup();
		}
	};

	$(function(){
		annoSource.init();
	});
})(jQuery);
<commit_msg>Refresh code editor on button click<commit_after>var annosource;

(function($){
	var inputs = {};

	annoSource = {
		init : function() {
			var t = this;
			t.widgets = [];
			inputs.$dialog = $('#anno-popup-source');
			inputs.$validate = $('#anno-source-validate');
			inputs.$insert = $('#anno-source-insert');
			inputs.$close = $('#anno-source-close');
			inputs.$all = $('.js-source-button');
			t.validationStatusID = '#validation-status';

			t.validator = window.annoValidation;

			inputs.$dialog.bind('wpdialogclose', annoSource.onClose);

			t.codemirror = CodeMirror.fromTextArea(document.getElementById('htmlSource'), {
				lineNumbers: true,
			});

			// Prevents CodeMirror from bugging out during show/hide/resize process
			$('body').on('click', '.mce-i-annosource', function(e) {
				e.preventDefault();
				t.codemirror.refresh();
			});

			// Re-evaluate the current xml
			inputs.$validate.on('click', function(e) {
				e.preventDefault();
				inputs.$all.prop('disabled', true);
				$(document).on('annoValidation', t.processValidation);
				t.validate().then(function(){
					inputs.$all.prop('disabled', false);
				});
			});

			// Insert the current XML back into the dom
			inputs.$insert.on('click', function(e) {
				e.preventDefault();
				$(document).on('annoValidation', t.processValidation);
				$(document).on('annoValidation', t.insertAlert);
				inputs.$all.prop('disabled', true);
				t.validate().then(function(){
					inputs.$all.prop('disabled', false);
				});
			});

			// Close the xml editor without inserting content
			inputs.$close.on('click', function(e) {
				e.preventDefault();
				t.close();
			});

			$('body').on('click', t.validationStatusID + ' a, .cm-error', function(e) {
				e.preventDefault();
				t.codemirror.focus();
				t.codemirror.setCursor($(this).data('line'), $(this).data('col'));
			});

			inputs.$dialog.bind('wpdialogbeforeopen', annoSource.beforeOpen);
		},
		validate : function(content) {
			var contentType;
			if (!content) {
				var content = this._getContent();
			}
			this._cleanup();
			contentType = this._getContentType();
			// Returns a promise
			return this.validator.validate(content, contentType);
		},
		insertContent : function() {
			this.editor.setContent('<!DOCTYPE sec SYSTEM "http://dtd.nlm.nih.gov/publishing/3.0/journalpublishing3.dtd">' + this.codemirror.getValue().trim() + '', {source_view : true});
			// Slightly hacky, but Textorum needs the content to be wrapped by a single element
			// Remove it after insertion.
			jQuery(this.editor.dom.select('div.body')[0].firstChild).unwrap();
		},
		// * Internal Helper Functions ***************
		_getContentType : function () {
			var contentType = '';
			if (!this.editor) {
				this.editor = top.tinymce.activeEditor;
			}

			if (this.editor.id == 'content') {
				contentType = 'body';
			}
			else if (this.editor.id == 'excerpt') {
				contentType = 'abstract';
			}

			return contentType;
		},
		_cleanup : function() {
			$(this.validationStatusID).html('');
		},
		_getContent : function() {
			return this.codemirror.getValue();
		},
		// * Event Callbacks ***************
		processValidation : function(e, data) {
			var t = annoSource, widget, errors = data.errors, insertEl, msg, $statusUL = $(t.validationStatusID);
			$(document).off('annoValidation', t.processValidation);
			if (data.status == 'error' || data.status == 'fatal') {
				for (var i = 0; i <= errors.length - 1; i++) {
					// Insert error at top of editor
					insertEl = document.createElement('a');
					$(insertEl).text(errors[i].fullMessage).data('col', errors[i].column).data('line', errors[i].line).attr('href', '#');
					$statusUL.append($(insertEl).wrap('

').parent());
				};
			}
			else if (data.status == 'success') {
				insertEl = document.createElement('li');
				$(insertEl).text(data.message);
				$statusUL.append($(insertEl));
			}
		},
		insertAlert : function(e, data) {
			var t = annoSource, status = data.status;
			$(document).off('annoValidation', t.insertAlert);
			if (status == 'error') {
				if (confirm('There are validation errors still. Are you sure you want to insert this content?')) { //@TODO i18n
					// onClose triggers cleanup
					t.insertContent();
					t.close();
				}
			}
			else if (status == 'fatal') {
				alert('The structure of the XML is broken. Please fix this and try again');
			}
			else {
				// onClose triggers cleanup
				t.insertContent();
				t.close();
			}
		},
		beforeOpen : function () {
			var t = annoSource;
			var contentType = t._getContentType();

			t.editor = top.tinymce.activeEditor;
			t.editorVal = t.editor.getContent({source_view : true}).replace(/^<!DOCTYPE[^>]*?>/, '');
			t.codemirror.setValue(t.editorVal);
			$(document).on('annoValidation', t.processValidation);
			t.validate(t.editorVal, contentType);
		},
		onClose : function () {
			var t = annoSource;
			t._cleanup();
		}
	};

	$(function(){
		annoSource.init();
	});
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

const Joi = require('joi');

const internals = {};

internals.validTypes = ['employer', 'insurance', 'health system'];

internals.updateOrganizationSchema = Joi.object({
    name: Joi.string().min(2).max(120),
    description: Joi.string().min(2).max(400),
    url: Joi.string().uri(),
    code: Joi.string().alphanum(),
    type: Joi.string().valid(internals.validTypes).insensitive()
});

module.exports = internals.updateOrganizationSchema;
<commit_msg>Deleted duplicate code in the validation schemas<commit_after>'use strict';

const Joi = require('joi');
const CreateOrganizationSchema = require('../validation/createOrganizationSchema');

const internals = {};

// internals.validTypes = ['employer', 'insurance', 'health system'];

// internals.updateOrganizationSchema = Joi.object({
//     name: Joi.string().min(2).max(120),
//     description: Joi.string().min(2).max(400),
//     url: Joi.string().uri(),
//     code: Joi.string().alphanum(),
//     type: Joi.string().valid(internals.validTypes).insensitive()
// });

internals.updateOrganizationSchema = CreateOrganizationSchema.optionalKeys([
    'name', 'description', 'url', 'code', 'type']);

module.exports = internals.updateOrganizationSchema;
<|endoftext|>