<commit_before>/* Directives */
angular.module('proso.geography.directives', ['proso.geography.templates'])

  .directive('placeLabel', ['colorScale', 'gettext', function(colorScale, gettext) {
    return {
      restrict : 'A',
      template : ' {{place.term.name}}',
      link : function($scope, elem) {
        elem.addClass('label');
        elem.addClass('label-default');
        elem.tooltip({
          html : true,
          placement: 'bottom',
          container: 'body',
          title : '
' +
                gettext('Odhad znalosti') +
                ' ' +
                  '' +
                  (10 * $scope.place.prediction) + ' / 10 ' +
                '' +
               '
'
        });
      }
    };
  }])

  .directive('blindMap', ['mapControler', 'places', 'singleWindowResizeFn',
        'getMapResizeFunction', '$parse',
      function(mapControler, places, singleWindowResizeFn,
        getMapResizeFunction, $parse) {
    return {
      restrict : 'E',
      templateUrl : 'static/tpl/map_tpl.html',
      link : function($scope, elem, attrs) {
        $scope.loading = true;
        $scope.name = places.getName($scope.part);
        $scope.practice = !attrs.showTooltips;
        var showTooltips = attrs.showTooltips !== undefined;

        var map = mapControler($scope.part, showTooltips, elem, function(m) {
          $scope.loading = false;
          var resize = getMapResizeFunction(m, elem, $scope.practice);
          singleWindowResizeFn(resize);
          resize();
          $scope.$eval(attrs.callback);
          $scope.$digest();
        });
        var model = $parse(attrs.map);
        //Set scope variable for the map
        model.assign($scope, map);
      },
      replace : true
    };
  }])

  .directive('email', function() {
    return {
      restrict : 'C',
      compile : function(elem) {
        var emailAddress = elem.html();
        emailAddress = emailAddress.replace('{zavinac}', '@');
        emailAddress = '' + emailAddress +
  '';
        elem.html(emailAddress);
      }
    };
  })

  .directive('atooltip', function() {
    return {
      restrict : 'C',
      link : function($scope, elem, attrs) {
        elem.tooltip({
          'placement' : attrs.placement || 'bottom',
          'container' : attrs.container,
        });
      }
    };
  })

  .directive('points', ['$timeout', 'events', function($timeout, events) {
    return {
      scope : true,
      restrict : 'C',
      link : function($scope, elem) {
        events.on('userUpdated', function(user) {
          $scope.user = user;
          if (user.points == 1) {
            $timeout(function() {
              elem.tooltip('show');
            }, 0);
          }
        });
      }
    };
  }])

  .directive('mapProgress', ['gettext', function(gettext) {
    return {
      restrict : 'C',
      template : '
' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                  '
',
      link : function($scope, elem, attrs) {
        attrs.$observe('skills', function(skills) {
          if(skills !== '') {
            $scope.skills = angular.fromJson(skills);
            $scope.skills.number_of_nonmastered_practiced_flashcards =
              $scope.skills.number_of_practiced_flashcards -
              ($scope.skills.number_of_mastered_flashcards || 0);
            elem.tooltip({
              html : true,
              placement: 'bottom',
              container: 'body',
              title : '
' +
                     gettext('Naučeno') + ' ' +
                     '' +
                       '' +
                       ($scope.skills.number_of_mastered_flashcards || 0) + ' / ' +
                       $scope.skills.number_of_flashcards +
                     '' +
                   '
' +
                   '
' +
                     gettext('Procvičováno') + ' ' +
                     '' +
                       '' +
                       ($scope.skills.number_of_nonmastered_practiced_flashcards || 0) + ' / ' +
                       $scope.skills.number_of_flashcards +
                     '' +
                   '
'
            });
          }
        });
      }
    };
  }])

  .directive('levelProgressBar',['userService', '$timeout', 'gettext',
      function(userService, $timeout, gettext) {
    return {
      restrict : 'C',
      template : '' +
                 '' +
                 '
' +
                   '
' +
                   '
' +
                 '
' +
                 '' +
                 '',
      link : function($scope, elem, attrs) {
        elem.addClass('level-wrapper');
          /*
        if (attrs.username) {
          userService.loadUser(attrs.username).success(function(data){
            $scope.level = user.getLevelInfo(data);
          });
        } else {
          $scope.level = user.getUser().getLevelInfo();
        }
          */
      }
    };
  }])

  .directive('myGooglePlus', ['$window', function ($window) {
    return {
      restrict: 'A',
      link: function (scope, element) {
        element.addClass('g-plus');
        scope.$watch(function () { return !!$window.gapi; },
          function (gapiIsReady) {
            if (gapiIsReady) {
              $window.gapi.plus.go(element.parent()[0]);
            }
          });
      }
    };
  }])

  .directive('myFbShare', ['$window', function ($window) {
    return {
      restrict: 'A',
      link: function (scope, element) {
        element.addClass('fb-share-button');
        scope.$watch(function () { return !!$window.FB; },
          function (fbIsReady) {
            if (fbIsReady) {
              $window.FB.XFBML.parse(element.parent()[0]);
            }
          });
      }
    };
  }])

  .directive('locationAppend', ['$rootScope', '$location',
      function ($rootScope, $location) {
    return {
      restrict: 'A',
      link: function ($scope, element, attrs) {
        var url = attrs.href.substring(0, 3);
        $rootScope.$on("$routeChangeSuccess", function() {
          element.attr('href', url + $location.path());
        });
      }
    };
  }])

  .directive('trackClick', ['$analytics', function ($analytics) {
    return {
      restrict: 'A',
      link: function (scope, element, attrs) {
        element.click(function(){
          $analytics.eventTrack('click', {
            category: attrs.trackClick,
            label: attrs.href,
          });
        });
      }
    };
  }])

  .directive('dynamicTitle', ['$rootScope', 'pageTitle', '$route', '$timeout',
      function ($rootScope, pageTitle, $route, $timeout) {
    return {
      restrict : 'A',
      scope : {},
      link : function (scope, element, attrs) {
        $rootScope.$on("$locationChangeSuccess", function() {
          $rootScope.title = pageTitle($route.current) + attrs.dynamicTitle;
          //console.log($rootScope.title);
          $timeout(function() {
            element.text($rootScope.title);
            //console.log($rootScope.title);
          }, 0, false);
        });
      }
    };
  }])

  .directive('setPlaceTypeNames', ['places', function (places) {
    return {
      restrict : 'A',
      link : function (scope, element, attrs) {
        var obj = angular.fromJson(attrs.setPlaceTypeNames);
        places.setPlaceTypeNames(obj);
      }
    };
  }])

  .directive('errorMessage', ['gettext', function (gettext) {
    return {
      restrict : 'A',
      template: '
' +
                  gettext("V aplikaci bohužel nastala chyba.") +
                '
',
    };
  }])

  .directive('showAfterXAnswers', ['$timeout', 'events', function($timeout, events) {
    return {
      scope : true,
      restrict : 'A',
      link : function($scope, elem, attrs) {
        var x = parseInt(attrs.showAfterXAnswers);
        events.on('userUpdated', function(user) {
          if (user.answered_count == x) {
            $timeout(function() {
              elem.tooltip({
                placement: 'right',
                title : elem.attr('tooltip'),
              });
              elem.tooltip('show');
            }, 100);
          }
        });
      }
    };
  }]);
<commit_msg>Fix map progress bar when some flashcards are mastered but no practiced<commit_after>/* Directives */
angular.module('proso.geography.directives', ['proso.geography.templates'])

  .directive('placeLabel', ['colorScale', 'gettext', function(colorScale, gettext) {
    return {
      restrict : 'A',
      template : ' {{place.term.name}}',
      link : function($scope, elem) {
        elem.addClass('label');
        elem.addClass('label-default');
        elem.tooltip({
          html : true,
          placement: 'bottom',
          container: 'body',
          title : '
' +
                gettext('Odhad znalosti') +
                ' ' +
                  '' +
                  (10 * $scope.place.prediction) + ' / 10 ' +
                '' +
               '
'
        });
      }
    };
  }])

  .directive('blindMap', ['mapControler', 'places', 'singleWindowResizeFn',
        'getMapResizeFunction', '$parse',
      function(mapControler, places, singleWindowResizeFn,
        getMapResizeFunction, $parse) {
    return {
      restrict : 'E',
      templateUrl : 'static/tpl/map_tpl.html',
      link : function($scope, elem, attrs) {
        $scope.loading = true;
        $scope.name = places.getName($scope.part);
        $scope.practice = !attrs.showTooltips;
        var showTooltips = attrs.showTooltips !== undefined;

        var map = mapControler($scope.part, showTooltips, elem, function(m) {
          $scope.loading = false;
          var resize = getMapResizeFunction(m, elem, $scope.practice);
          singleWindowResizeFn(resize);
          resize();
          $scope.$eval(attrs.callback);
          $scope.$digest();
        });
        var model = $parse(attrs.map);
        //Set scope variable for the map
        model.assign($scope, map);
      },
      replace : true
    };
  }])

  .directive('email', function() {
    return {
      restrict : 'C',
      compile : function(elem) {
        var emailAddress = elem.html();
        emailAddress = emailAddress.replace('{zavinac}', '@');
        emailAddress = '' + emailAddress +
  '';
        elem.html(emailAddress);
      }
    };
  })

  .directive('atooltip', function() {
    return {
      restrict : 'C',
      link : function($scope, elem, attrs) {
        elem.tooltip({
          'placement' : attrs.placement || 'bottom',
          'container' : attrs.container,
        });
      }
    };
  })

  .directive('points', ['$timeout', 'events', function($timeout, events) {
    return {
      scope : true,
      restrict : 'C',
      link : function($scope, elem) {
        events.on('userUpdated', function(user) {
          $scope.user = user;
          if (user.points == 1) {
            $timeout(function() {
              elem.tooltip('show');
            }, 0);
          }
        });
      }
    };
  }])

  .directive('mapProgress', ['gettext', function(gettext) {
    return {
      restrict : 'C',
      template : '
' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                  '
',
      link : function($scope, elem, attrs) {
        attrs.$observe('skills', function(skills) {
          if(skills !== '') {
            $scope.skills = angular.fromJson(skills);
            $scope.skills.number_of_nonmastered_practiced_flashcards =
              Math.max(0, $scope.skills.number_of_practiced_flashcards -
              ($scope.skills.number_of_mastered_flashcards || 0));
            elem.tooltip({
              html : true,
              placement: 'bottom',
              container: 'body',
              title : '
' +
                     gettext('Naučeno') + ' ' +
                     '' +
                       '' +
                       ($scope.skills.number_of_mastered_flashcards || 0) + ' / ' +
                       $scope.skills.number_of_flashcards +
                     '' +
                   '
' +
                   '
' +
                     gettext('Procvičováno') + ' ' +
                     '' +
                       '' +
                       ($scope.skills.number_of_nonmastered_practiced_flashcards || 0) + ' / ' +
                       $scope.skills.number_of_flashcards +
                     '' +
                   '
'
            });
          }
        });
      }
    };
  }])

  .directive('levelProgressBar',['userService', '$timeout', 'gettext',
      function(userService, $timeout, gettext) {
    return {
      restrict : 'C',
      template : '' +
                 '' +
                 '
' +
                   '
' +
                   '
' +
                 '
' +
                 '' +
                 '',
      link : function($scope, elem, attrs) {
        elem.addClass('level-wrapper');
          /*
        if (attrs.username) {
          userService.loadUser(attrs.username).success(function(data){
            $scope.level = user.getLevelInfo(data);
          });
        } else {
          $scope.level = user.getUser().getLevelInfo();
        }
          */
      }
    };
  }])

  .directive('myGooglePlus', ['$window', function ($window) {
    return {
      restrict: 'A',
      link: function (scope, element) {
        element.addClass('g-plus');
        scope.$watch(function () { return !!$window.gapi; },
          function (gapiIsReady) {
            if (gapiIsReady) {
              $window.gapi.plus.go(element.parent()[0]);
            }
          });
      }
    };
  }])

  .directive('myFbShare', ['$window', function ($window) {
    return {
      restrict: 'A',
      link: function (scope, element) {
        element.addClass('fb-share-button');
        scope.$watch(function () { return !!$window.FB; },
          function (fbIsReady) {
            if (fbIsReady) {
              $window.FB.XFBML.parse(element.parent()[0]);
            }
          });
      }
    };
  }])

  .directive('locationAppend', ['$rootScope', '$location',
      function ($rootScope, $location) {
    return {
      restrict: 'A',
      link: function ($scope, element, attrs) {
        var url = attrs.href.substring(0, 3);
        $rootScope.$on("$routeChangeSuccess", function() {
          element.attr('href', url + $location.path());
        });
      }
    };
  }])

  .directive('trackClick', ['$analytics', function ($analytics) {
    return {
      restrict: 'A',
      link: function (scope, element, attrs) {
        element.click(function(){
          $analytics.eventTrack('click', {
            category: attrs.trackClick,
            label: attrs.href,
          });
        });
      }
    };
  }])

  .directive('dynamicTitle', ['$rootScope', 'pageTitle', '$route', '$timeout',
      function ($rootScope, pageTitle, $route, $timeout) {
    return {
      restrict : 'A',
      scope : {},
      link : function (scope, element, attrs) {
        $rootScope.$on("$locationChangeSuccess", function() {
          $rootScope.title = pageTitle($route.current) + attrs.dynamicTitle;
          //console.log($rootScope.title);
          $timeout(function() {
            element.text($rootScope.title);
            //console.log($rootScope.title);
          }, 0, false);
        });
      }
    };
  }])

  .directive('setPlaceTypeNames', ['places', function (places) {
    return {
      restrict : 'A',
      link : function (scope, element, attrs) {
        var obj = angular.fromJson(attrs.setPlaceTypeNames);
        places.setPlaceTypeNames(obj);
      }
    };
  }])

  .directive('errorMessage', ['gettext', function (gettext) {
    return {
      restrict : 'A',
      template: '
' +
                  gettext("V aplikaci bohužel nastala chyba.") +
                '
',
    };
  }])

  .directive('showAfterXAnswers', ['$timeout', 'events', function($timeout, events) {
    return {
      scope : true,
      restrict : 'A',
      link : function($scope, elem, attrs) {
        var x = parseInt(attrs.showAfterXAnswers);
        events.on('userUpdated', function(user) {
          if (user.answered_count == x) {
            $timeout(function() {
              elem.tooltip({
                placement: 'right',
                title : elem.attr('tooltip'),
              });
              elem.tooltip('show');
            }, 100);
          }
        });
      }
    };
  }]);
<|endoftext|>


<commit_before>import {Container} from 'aurelia-dependency-injection';
import {Behavior, CompositionEngine, ViewSlot, ViewResources} from 'aurelia-templating';

export class Compose {
  static metadata(){
    return Behavior
      .customElement('compose')
      .withProperty('model')
      .withProperty('view')
      .withProperty('view-model')
      .noView();
  }

  static inject(){ return [Container,CompositionEngine,ViewSlot,ViewResources]; }
	constructor(container, compositionEngine, viewSlot, viewResources){
		this.container = container;
		this.compositionEngine = compositionEngine;
		this.viewSlot = viewSlot;
    this.viewResources = viewResources;
	}

	bind(executionContext){
		this.executionContext = executionContext;
		processInstruction(this, {
			view:this.view,
      viewModel:this.viewModel,
      model:this.model
		});
	}

	modelChanged(newValue, oldValue){
		if(this.viewModel && typeof this.viewModel.activate === 'function'){
			this.viewModel.activate(newValue);
		}
  }

  viewChanged(newValue, oldValue){
  	processInstruction(this, { view:newValue });
  }

  viewModelChanged(newValue, oldValue){
  	processInstruction(this, { viewModel:newValue });
  }
}

function processInstruction(composer, instruction){
  composer.compositionEngine.compose(Object.assign(instruction, {
    executionContext:composer.executionContext,
    container:composer.container,
    viewSlot:composer.viewSlot,
    viewResources:composer.viewResources,
    currentBehavior:composer.current
  })).then(next => {
    composer.current = next;
  });
}<commit_msg>fix(compose): incorrect property name<commit_after>import {Container} from 'aurelia-dependency-injection';
import {Behavior, CompositionEngine, ViewSlot, ViewResources} from 'aurelia-templating';

export class Compose {
  static metadata(){
    return Behavior
      .customElement('compose')
      .withProperty('model')
      .withProperty('view')
      .withProperty('viewModel')
      .noView();
  }

  static inject(){ return [Container,CompositionEngine,ViewSlot,ViewResources]; }
	constructor(container, compositionEngine, viewSlot, viewResources){
		this.container = container;
		this.compositionEngine = compositionEngine;
		this.viewSlot = viewSlot;
    this.viewResources = viewResources;
	}

	bind(executionContext){
		this.executionContext = executionContext;
		processInstruction(this, {
			view:this.view,
      viewModel:this.viewModel,
      model:this.model
		});
	}

	modelChanged(newValue, oldValue){
		if(this.viewModel && typeof this.viewModel.activate === 'function'){
			this.viewModel.activate(newValue);
		}
  }

  viewChanged(newValue, oldValue){
  	processInstruction(this, { view:newValue });
  }

  viewModelChanged(newValue, oldValue){
  	processInstruction(this, { viewModel:newValue });
  }
}

function processInstruction(composer, instruction){
  composer.compositionEngine.compose(Object.assign(instruction, {
    executionContext:composer.executionContext,
    container:composer.container,
    viewSlot:composer.viewSlot,
    viewResources:composer.viewResources,
    currentBehavior:composer.current
  })).then(next => {
    composer.current = next;
  });
}<|endoftext|>


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

var io = require('socket.io')
  , util = require('util')
  , uuid = require('node-uuid')
  , Formatter = require('./formatter')
  , serviceBusInterface = require('./servicebusinterface');

exports = module.exports = ServiceBusStore;
ServiceBusStore.Client = Client;

function ServiceBusStore(options) {
  io.Store.apply(this, arguments);

  this.nodeId = (options && options.nodeId) || uuid();
  this.formatter = this.createFormatter(this.nodeId);
  this.sb = this.createServiceBusInterface(options);
  this.subscribers = {};

  this.sb.start();
}

util.inherits(ServiceBusStore, io.Store);

/**
 * Publish a message
 *
 * @param {String} name name of message
 *
 * other arguments are arguments for the message
 *
 * @api private
 */
ServiceBusStore.prototype.publish = function (name) {
  var args = Array.prototype.slice.call(arguments, 1);
  this.sb.send(this.formatter.pack(name, args));
  this.emit.apply(this, ['publish', name].concat(args));
}

/**
 * Subscribe to received messages
 *
 * @param {string} name name of message received
 *
 * @param {function} consumer function to call when message is received
 *
 * @api private
 */
ServiceBusStore.prototype.subscribe = function (name, consumer) {
  log('SbStore has new subscriber for %s events', name);
  var subscribers = this.subscribers[name] || [];
  subscribers.push(consumer);
  this.subscribers[name] = subscribers;

  this.emit('subscribe', name, consumer);
}

ServiceBusStore.prototype.unsubscribe = function (name, consumer) {
  log('SbStore unsubscribing from %s', name);
  var subscribers = this.subscribers[name] || [];
  subscribers = subscribers.filter(function (item) { item !== consumer; });
  this.subscribers[name] = subscribers;

  this.emit('unsubscribe', name, consumer);
}

ServiceBusStore.prototype.destroy = function () {
  Store.prototype.destroy.call(this);
  this.sb.stop();
  this.subscribers = {};
}

ServiceBusStore.prototype.receiveMessage = function (sbMessage) {
  var message = this.formatter.unpack(sbMessage);
  log('Store nodeId %s Received message of type %s from node %s', this.nodeId, message.name, message.nodeId);
  if (message.nodeId !== this.nodeId) {
    log('Store nodeId %s sending message to subscribers', this.nodeId);
    var subscribers = this.subscribers[message.name] || [];
    subscribers.forEach(function (sub) {
      sub.apply(null, message.args);
    });
  }
}

ServiceBusStore.prototype.createServiceBusInterface = function createServiceBusInterface(options) {
  this.sb = new serviceBusInterface(options.serviceBusService, options.topic, options.subscription);
}

ServiceBusStore.prototype.createFormatter = function (nodeId) {
  return new Formatter(nodeId);
}

function Client() {
  io.Store.Client.apply(this, arguments);
  this.data = {};
}

util.inherits(ServiceBusStore.Client, io.Store.Client);

/**
 * Get data stored under a key
 *
 * @param {Object} key key to retrieve data for
 * @param {function(err, value)} fn
 *     callback function that received the retrieved value
 *
 * @return {Client} this client object
 */
Client.prototype.get = function (key, fn) {
  var self = this;
  invoke(fn, null, self.data[key] || null);
  return this;
}

/**
 * Store client data for a key
 *
 * @param {Object} key key to store data under
 * @param {Object} value value to store
 * @param {function(err)} fn callback function when set completed
 *
 * @return {Client} this client object.
 */
Client.prototype.set = function (key, value, fn) {
  var self = this;
  this.data[key] = value;
  invoke(fn, null);
  return this;
}

/**
 * Check if data for a key has been stored
 *
 * @param {Object} key
 *    key to check for
 *
 * @param {function(err, hasKey)} fn
 *    callback function that receives result
 *
 * @return {Client} this client object
 */
Client.prototype.has = function (key, fn) {
  invoke(fn, null, key in this.data);
  return this;
}

/**
 * Delete data for a key
 *
 * @param {Object} key
 *    key to delete
 *
 * @param {function(err)} fn
 *    callback function invoked when deletion is done
 *
 * @return {Client}
 *    this client object
 */
Client.prototype.del = function (key, fn) {
  delete this.data[key];
  invoke(fn, null);
  return this;
}

/**
 * Delete all data stored by this client
 *
 * @param {Number} expiration
 *    timeout in seconds before deleting data. If
 *    not specified, deletes data immediately.
 *
 * @return {Client}
 *    this client object
 */
Client.prototype.destroy = function (expiration) {
  if('number' !== typeof expiration) {
    this.data = {};
  } else {
    var self = this;
    setTimeout(function () {
      self.data = {};
    }, expiration * 1000);
  }
  return this;
}

// Helper function to invoke callbacks
// Invoke on next event loop turn in case
// we expand to storing this data off the box
// and need actual async.
function invoke(fn) {
  if (fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    process.nextTick(function() {
      fn.apply(null, args);
    });
  }
}

// Helper function for logging
function log() {
  console.log(util.format.apply(null, arguments));
}
<commit_msg>Fixing casing<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var io = require('socket.io')
  , util = require('util')
  , uuid = require('node-uuid')
  , Formatter = require('./formatter')
  , ServiceBusInterface = require('./servicebusinterface');

exports = module.exports = ServiceBusStore;
ServiceBusStore.Client = Client;

function ServiceBusStore(options) {
  io.Store.apply(this, arguments);

  this.nodeId = (options && options.nodeId) || uuid();
  this.formatter = this.createFormatter(this.nodeId);
  this.sb = this.createServiceBusInterface(options);
  this.subscribers = {};

  this.sb.start();
}

util.inherits(ServiceBusStore, io.Store);

/**
 * Publish a message
 *
 * @param {String} name name of message
 *
 * other arguments are arguments for the message
 *
 * @api private
 */
ServiceBusStore.prototype.publish = function (name) {
  var args = Array.prototype.slice.call(arguments, 1);
  this.sb.send(this.formatter.pack(name, args));
  this.emit.apply(this, ['publish', name].concat(args));
}

/**
 * Subscribe to received messages
 *
 * @param {string} name name of message received
 *
 * @param {function} consumer function to call when message is received
 *
 * @api private
 */
ServiceBusStore.prototype.subscribe = function (name, consumer) {
  log('SbStore has new subscriber for %s events', name);
  var subscribers = this.subscribers[name] || [];
  subscribers.push(consumer);
  this.subscribers[name] = subscribers;

  this.emit('subscribe', name, consumer);
}

ServiceBusStore.prototype.unsubscribe = function (name, consumer) {
  log('SbStore unsubscribing from %s', name);
  var subscribers = this.subscribers[name] || [];
  subscribers = subscribers.filter(function (item) { item !== consumer; });
  this.subscribers[name] = subscribers;

  this.emit('unsubscribe', name, consumer);
}

ServiceBusStore.prototype.destroy = function () {
  Store.prototype.destroy.call(this);
  this.sb.stop();
  this.subscribers = {};
}

ServiceBusStore.prototype.receiveMessage = function (sbMessage) {
  var message = this.formatter.unpack(sbMessage);
  log('Store nodeId %s Received message of type %s from node %s', this.nodeId, message.name, message.nodeId);
  if (message.nodeId !== this.nodeId) {
    log('Store nodeId %s sending message to subscribers', this.nodeId);
    var subscribers = this.subscribers[message.name] || [];
    subscribers.forEach(function (sub) {
      sub.apply(null, message.args);
    });
  }
}

ServiceBusStore.prototype.createServiceBusInterface = function createServiceBusInterface(options) {
  this.sb = new ServiceBusInterface(options.serviceBusService, options.topic, options.subscription);
}

ServiceBusStore.prototype.createFormatter = function (nodeId) {
  return new Formatter(nodeId);
}

function Client() {
  io.Store.Client.apply(this, arguments);
  this.data = {};
}

util.inherits(ServiceBusStore.Client, io.Store.Client);

/**
 * Get data stored under a key
 *
 * @param {Object} key key to retrieve data for
 * @param {function(err, value)} fn
 *     callback function that received the retrieved value
 *
 * @return {Client} this client object
 */
Client.prototype.get = function (key, fn) {
  var self = this;
  invoke(fn, null, self.data[key] || null);
  return this;
}

/**
 * Store client data for a key
 *
 * @param {Object} key key to store data under
 * @param {Object} value value to store
 * @param {function(err)} fn callback function when set completed
 *
 * @return {Client} this client object.
 */
Client.prototype.set = function (key, value, fn) {
  var self = this;
  this.data[key] = value;
  invoke(fn, null);
  return this;
}

/**
 * Check if data for a key has been stored
 *
 * @param {Object} key
 *    key to check for
 *
 * @param {function(err, hasKey)} fn
 *    callback function that receives result
 *
 * @return {Client} this client object
 */
Client.prototype.has = function (key, fn) {
  invoke(fn, null, key in this.data);
  return this;
}

/**
 * Delete data for a key
 *
 * @param {Object} key
 *    key to delete
 *
 * @param {function(err)} fn
 *    callback function invoked when deletion is done
 *
 * @return {Client}
 *    this client object
 */
Client.prototype.del = function (key, fn) {
  delete this.data[key];
  invoke(fn, null);
  return this;
}

/**
 * Delete all data stored by this client
 *
 * @param {Number} expiration
 *    timeout in seconds before deleting data. If
 *    not specified, deletes data immediately.
 *
 * @return {Client}
 *    this client object
 */
Client.prototype.destroy = function (expiration) {
  if('number' !== typeof expiration) {
    this.data = {};
  } else {
    var self = this;
    setTimeout(function () {
      self.data = {};
    }, expiration * 1000);
  }
  return this;
}

// Helper function to invoke callbacks
// Invoke on next event loop turn in case
// we expand to storing this data off the box
// and need actual async.
function invoke(fn) {
  if (fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    process.nextTick(function() {
      fn.apply(null, args);
    });
  }
}

// Helper function for logging
function log() {
  console.log(util.format.apply(null, arguments));
}
<|endoftext|>


<commit_before>// selleck.js —- javascript templating

var selleck = (function() {
  var cache = {};
  // A forgiving object[key]
  var getValue = function(obj, key) {
    var gv = function(obj, keys) {
      if (keys.length === 0) {
        return obj;
      }
      first = keys.shift();
      // empty return on missing key
      if (!obj.hasOwnProperty(first)) return '';
      return gv(obj[first], keys);
    };
    var keys = key.split('.');
    return gv(obj, keys);
  };
  var getArray = function(obj, key) {
    // XXX more checks on whether gotten value is array?
    return getValue(obj, key) || [];
  };
  // expand all partials
  var expand = function(template, partials) {
    template = template.replace(/{>([\w.]+)}/g, function(str, partialKey) {
      // get rid of extra whitespace at the end of the partial
      return getValue(partials, partialKey).replace(/\s+$/, '');
    });
    return template;
  };
  var compile = function(template, partials) {
    var expanded = template = expand(template, partials);
    //console.log(expanded);
    // first check cache and return if cached
    if (cache[expanded]) {
      return cache[expanded];
    }
    // compile if not cached
    var replacement;
    var levels = {'for':0, 'if': 0};
    var nearby = function(offset, s) {
      return s.slice(offset-30, offset+10);
    };
    // replace simple key tags like {foo}
    template = template.replace(/{([\w.]+)}/g, function(str, key) {
      return '\'+getValue(context,\''+key+'\')+\'';
    });
    // replace logic tags like {for foo in bar} and {if foo}
    template = template.replace(/((?:\n|\r|\r\n)[ \t]*|){(\/?)(for|if|)( +|)(not +|)((\w+) +in +|)([\w.]+|)}(?:([ \t]*(?=\n|\r|\r\n))|)/g, function(str, newlineBefore, close, statement, statementSpace, ifNot, forIn, iterVar, key, newlineAfter, offset, s) {
      if (newlineBefore && newlineAfter !== undefined) {
        newlineBefore = '';
      }
      if (statement === 'for' && statementSpace && iterVar && key) { // {for foo in bar}
        levels['for']++;
        replacement = newlineBefore+'\';var '+iterVar+'A=getArray(context,\''+key+'\');for(var '+iterVar+'I=0;'+iterVar+'I<'+iterVar+'A.length;'+iterVar+'I++){context[\''+iterVar+'\']='+iterVar+'A['+iterVar+'I];buffer+=\'';
      } else if (statement === 'if' && statementSpace && key) { // {if foo} or {if not foo}
        levels['if']++;
        replacement = newlineBefore+'\';if('+(ifNot?'!':'')+'getValue(context,\''+key+'\')){buffer+=\'';
      } else if (close && statement) { // {/for} or {/if}
        if (levels[statement] === 0) {
          console.warn('extra {/'+statement+'} ignored at "'+nearby(offset, s)+'"');
          replacement = '';
        } else {
          levels[statement]--;
          replacement = newlineBefore+'\';}buffer+=\'';
        }
      } else { // match on {} -- return str
        replacement = str;
      }
      return replacement;
    });
    for (statement in levels) {
      for (var i=0; i<levels[statement]; i++) {
        console.warn('extra "'+statement+'" closed at end of template');
        template = template+'\';}buffer+=\'';
      }
    }
    // wrap in function
    template = '(function(){return function(context){var buffer=\''+template+'\';return buffer}})()';
    // ready newlines for eval
    template = template.replace(/\n/g, '\\n');
    //console.log(template);
    // cache template
    cache[expanded] = eval(template);
    return cache[expanded];
  };
  var render = function(template, context, partials) {
    var compiled = compile(template, partials);
    return compiled(context);
  };
  return {
    compile: compile,
    render: render
  };
})();

// for commonJS
for (attribute in selleck) {
  if (selleck.hasOwnProperty(attribute)) {
    exports[attribute] = selleck[attribute];
  }
}
<commit_msg>Cleanup and better docstrings<commit_after>// selleck.js —- javascript templating

var selleck = (function() {
  var cache = {};
  // A forgiving object[key]
  var getValue = function(obj, key) {
    var gv = function(obj, keys) {
      if (keys.length === 0) {
        return obj;
      }
      first = keys.shift();
      // empty return on missing key
      if (!obj.hasOwnProperty(first)) return '';
      return gv(obj[first], keys);
    };
    var keys = key.split('.');
    return gv(obj, keys);
  };
  var getArray = function(obj, key) {
    // XXX more checks on whether gotten value is array?
    return getValue(obj, key) || [];
  };
  // expand all partials
  var expand = function(template, partials) {
    template = template.replace(/{>([\w.]+)}/g, function(str, partialKey) {
      // get rid of extra whitespace at the end of the partial
      return getValue(partials, partialKey).replace(/\s+$/, '');
    });
    return template;
  };
  var compile = function(template, partials) {
    var expanded = template = expand(template, partials);
    // first check cache and return if cached
    if (cache[expanded]) {
      return cache[expanded];
    }
    // compile if not cached
    var replacement;
    var levels = {'for':0, 'if': 0};
    var nearby = function(offset, s) {
      return s.slice(offset-30, offset+10);
    };
    // replace simple key tags (like {foo})
    template = template.replace(/{([\w.]+)}/g, function(str, key) {
      return '\'+getValue(context,\''+key+'\')+\'';
    });
    // replace logic tags (like {for foo in bar} and {if foo})
    template = template.replace(/((?:\n|\r|\r\n)[ \t]*|){(\/?)(for|if|)( +|)(not +|)((\w+) +in +|)([\w.]+|)}(?:([ \t]*(?=\n|\r|\r\n))|)/g, function(str, newlineBefore, close, statement, statementSpace, ifNot, forIn, iterVar, key, newlineAfter, offset, s) {
      // if a logic tag is on a line by itself remove preceding newline and
      // whitespace
      if (newlineBefore && newlineAfter !== undefined) {
        newlineBefore = '';
      }
      // {for foo in bar}
      if (statement === 'for' && statementSpace && iterVar && key) {
        levels['for']++;
        replacement = newlineBefore+'\';var '+iterVar+'A=getArray(context,\''+key+'\');for(var '+iterVar+'I=0;'+iterVar+'I<'+iterVar+'A.length;'+iterVar+'I++){context[\''+iterVar+'\']='+iterVar+'A['+iterVar+'I];buffer+=\'';
      // {if foo} or {if not foo}
      } else if (statement === 'if' && statementSpace && key) {
        levels['if']++;
        replacement = newlineBefore+'\';if('+(ifNot?'!':'')+'getValue(context,\''+key+'\')){buffer+=\'';
      // {/for} or {/if}
      } else if (close && statement) {
        if (levels[statement] === 0) {
          console.warn('extra {/'+statement+'} ignored at "'+nearby(offset, s)+'"');
          replacement = '';
        } else {
          levels[statement]--;
          replacement = newlineBefore+'\';}buffer+=\'';
        }
      // not a tag, don't replace
      } else {
        replacement = str;
      }
      return replacement;
    });
    // close extra fors and ifs
    for (statement in levels) {
      for (var i=0; i<levels[statement]; i++) {
        console.warn('extra "'+statement+'" closed at end of template');
        template = template+'\';}buffer+=\'';
      }
    }
    // ready newlines for eval
    template = template.replace(/\n/g, '\\n');
    // wrap in function
    template = '(function(){return function(context){var buffer=\''+template+'\';return buffer}})()';
    // cache template
    cache[expanded] = eval(template);
    return cache[expanded];
  };
  var render = function(template, context, partials) {
    var compiled = compile(template, partials);
    return compiled(context);
  };
  return {
    compile: compile,
    render: render
  };
})();

// populate exports for commonJS
for (attribute in selleck) {
  if (selleck.hasOwnProperty(attribute)) {
    exports[attribute] = selleck[attribute];
  }
}
<|endoftext|>


<commit_before>var EventLog = require('./eventLog')
  ,	Faye = require('faye')
  , Heartbeat = require('./heartbeat')
  , Message = require('./message');

function Session(service, principal, accessToken) {
    var self=this;

	this.service = service;
	this.principal = principal;
    this.accessToken = accessToken;

	this.fayeClient = new Faye.Client(this.service.config.realtime_endpoint);
    this.fayeClient.addExtension({
        outgoing: function(message, callback) {
            message.ext = message.ext || {};
            message.ext.access_token = self.accessToken.token;
            callback(message);
        }
    });

    this.subscriptions = [];
    this.authFailureCallback = function() {};

	this.log = new EventLog(this);
    this.log.start();

    this.heartbeat = new Heartbeat(this);
    this.heartbeat.start();
}

Session.prototype.clearCredentials = function() {
    console.log("principal: " + this.principal);
    this.service.clearCredentials(this.principal);
};

Session.prototype.close = function() {
    this.subscriptions.forEach(function(subscription) {
        subscription.cancel();
    });

    this.fayeClient.disconnect();
    this.fayeClient = null;

    this.heartbeat.stop();
    this.log.stop();
};

Session.prototype.onAuthFailure = function(callback) {
    this.authFailureCallback = callback;
};

Session.prototype.onMessage = function(callback) {
    if (!this.fayeClient) return callback("Session previously closed");

    var self = this;

    var subscription = this.fayeClient.subscribe('/messages', function(messageJSON) {
        console.log("realtime message received: " + messageJSON);
        callback(new Message(JSON.parse(messageJSON)));
    });

    subscription.errback(function(error) {
        console.log("realtime subscription error: " + error);
        if (self.authFailureCallback) self.authFailureCallback();
    });

    this.subscriptions.push(subscription);
};

Session.prototype.impersonate = function(principal, callback) {
    this.service.impersonate(this, principal, callback);
};

module.exports = Session;<commit_msg>use new scoped messages realtime endpoint<commit_after>var EventLog = require('./eventLog')
  ,	Faye = require('faye')
  , Heartbeat = require('./heartbeat')
  , Message = require('./message');

function Session(service, principal, accessToken) {
    var self=this;

	this.service = service;
	this.principal = principal;
    this.accessToken = accessToken;

	this.fayeClient = new Faye.Client(this.service.config.realtime_endpoint);
    this.fayeClient.addExtension({
        outgoing: function(message, callback) {
            message.ext = message.ext || {};
            message.ext.access_token = self.accessToken.token;
            callback(message);
        }
    });

    this.subscriptions = [];
    this.authFailureCallback = function() {};

	this.log = new EventLog(this);
    this.log.start();

    this.heartbeat = new Heartbeat(this);
    this.heartbeat.start();
}

Session.prototype.clearCredentials = function() {
    console.log("principal: " + this.principal);
    this.service.clearCredentials(this.principal);
};

Session.prototype.close = function() {
    this.subscriptions.forEach(function(subscription) {
        subscription.cancel();
    });

    this.fayeClient.disconnect();
    this.fayeClient = null;

    this.heartbeat.stop();
    this.log.stop();
};

Session.prototype.onAuthFailure = function(callback) {
    this.authFailureCallback = callback;
};

Session.prototype.onMessage = function(callback) {
    if (!this.fayeClient) return callback("Session previously closed");

    var self = this;

    var subscription = this.fayeClient.subscribe('/messages/' + this.principal.id, function(messageJSON) {
        console.log("realtime message received: " + messageJSON);
        callback(new Message(JSON.parse(messageJSON)));
    });

    subscription.errback(function(error) {
        console.log("realtime subscription error: " + error);
        if (self.authFailureCallback) self.authFailureCallback();
    });

    this.subscriptions.push(subscription);
};

Session.prototype.impersonate = function(principal, callback) {
    this.service.impersonate(this, principal, callback);
};

module.exports = Session;<|endoftext|>


<commit_before>var crypto = require('crypto');
var keystone = require('../');
var scmp = require('scmp');
var utils = require('keystone-utils');

/**
 * Creates a hash of str with Keystone's cookie secret.
 * Only hashes the first half of the string.
 */
function hash (str) {
	// force type
	str = '' + str;
	// get the first half
	str = str.substr(0, Math.round(str.length / 2));
	// hash using sha256
	return crypto
		.createHmac('sha256', keystone.get('cookie secret'))
		.update(str)
		.digest('base64')
		.replace(/\=+$/, '');
}

/**
 * Signs in a user using user obejct
 *
 * @param {Object} user - user object
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} onSuccess callback, is passed the User instance
 */

function signinWithUser (user, req, res, onSuccess) {
	if (arguments.length < 4) {
		throw new Error('keystone.session.signinWithUser requires user, req and res objects, and an onSuccess callback.');
	}
	if (typeof user !== 'object') {
		throw new Error('keystone.session.signinWithUser requires user to be an object.');
	}
	if (typeof req !== 'object') {
		throw new Error('keystone.session.signinWithUser requires req to be an object.');
	}
	if (typeof res !== 'object') {
		throw new Error('keystone.session.signinWithUser requires res to be an object.');
	}
	if (typeof onSuccess !== 'function') {
		throw new Error('keystone.session.signinWithUser requires onSuccess to be a function.');
	}
	req.session.regenerate(function () {
		req.user = user;
		req.session.userId = user.id;
		// if the user has a password set, store a persistence cookie to resume sessions
		if (keystone.get('cookie signin') && user.password) {
			var userToken = user.id + ':' + hash(user.password);
			var cookieOpts = { signed: true, httpOnly: true, maxAge: keystone.get('cookie signin expire') || 900000 };
			if (keystone.get('cookie signin domain')) {
				cookieOpts.domain = keystone.get('cookie signin domain');
			}
			res.cookie('keystone.uid', userToken, cookieOpts);
		}
		onSuccess(user);
	});
}

exports.signinWithUser = signinWithUser;

var postHookedSigninWithUser = function (user, req, res, onSuccess, onFail) {
	keystone.callHook(user, 'post:signin', function (err) {
		if (err) {
			return onFail(err);
		}
		exports.signinWithUser(user, req, res, onSuccess, onFail);
	});
};

/**
 * Signs in a user user matching the lookup filters
 *
 * @param {Object} lookup - must contain email and password
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} onSuccess callback, is passed the User instance
 * @param {function()} onFail callback
 */

var doSignin = function (lookup, req, res, onSuccess, onFail) {
	if (!lookup) {
		return onFail(new Error('session.signin requires a User ID or Object as the first argument'));
	}
	var User = keystone.list(keystone.get('user model'));
	if (typeof lookup.email === 'string' && typeof lookup.password === 'string') {
		// ensure that it is an email, we don't want people being able to sign in by just using "\." and a haphazardly correct password.
		if (!utils.isEmail(lookup.email)) {
			return onFail(new Error('Incorrect email or password'));
		}
		// create regex for email lookup with special characters escaped
		var emailRegExp = new RegExp('^' + utils.escapeRegExp(lookup.email) + '$', 'i');
		// match email address and password
		User.model.findOne({ email: emailRegExp }).exec(function (err, user) {
			if (user) {
				user._.password.compare(lookup.password, function (err, isMatch) {
					if (!err && isMatch) {
						postHookedSigninWithUser(user, req, res, onSuccess, onFail);
					} else {
						onFail(err || new Error('Incorrect email or password'));
					}
				});
			} else {
				onFail(err);
			}
		});
	} else {
		lookup = '' + lookup;
		// match the userId, with optional password check
		var userId = (lookup.indexOf(':') > 0) ? lookup.substr(0, lookup.indexOf(':')) : lookup;
		var passwordCheck = (lookup.indexOf(':') > 0) ? lookup.substr(lookup.indexOf(':') + 1) : false;
		User.model.findById(userId).exec(function (err, user) {
			if (user && (!passwordCheck || scmp(passwordCheck, hash(user.password)))) {
				postHookedSigninWithUser(user, req, res, onSuccess, onFail);
			} else {
				onFail(err || new Error('Incorrect user or password'));
			}
		});
	}
};

exports.signin = function (lookup, req, res, onSuccess, onFail) {
	keystone.callHook({}, 'pre:signin', function (err) {
		if (err) {
			return onFail(err);
		}
		doSignin(lookup, req, res, onSuccess, onFail);
	});
};

/**
 * Signs the current user out and resets the session
 *
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} next callback
 */

exports.signout = function (req, res, next) {
	keystone.callHook(req.user, 'pre:signout', function (err) {
		if (err) {
			console.log("An error occurred in signout 'pre' middleware", err);
		}
		res.clearCookie('keystone.uid');
		req.user = null;
		req.session.regenerate(function (err) {
			if (err) {
				return next(err);
			}
			keystone.callHook({}, 'post:signout', function (err) {
				if (err) {
					console.log("An error occurred in signout 'post' middleware", err);
				}
				next();
			});
		});
	});
};

/**
 * Middleware to ensure session persistence across server restarts
 *
 * Looks for a userId cookie, and if present, and there is no user signed in,
 * automatically signs the user in.
 *
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} next callback
 */

exports.persist = function (req, res, next) {
	var User = keystone.list(keystone.get('user model'));
	if (!req.session) {
		console.error('\nKeystoneJS Runtime Error:\n\napp must have session middleware installed. Try adding "express-session" to your express instance.\n');
		process.exit(1);
	}
	if (keystone.get('cookie signin') && !req.session.userId && req.signedCookies['keystone.uid'] && req.signedCookies['keystone.uid'].indexOf(':') > 0) {
		exports.signin(req.signedCookies['keystone.uid'], req, res, function () {
			next();
		}, function (err) {
			res.clearCookie('keystone.uid');
			req.user = null;
			next();
		});
	} else if (req.session.userId) {
		User.model.findById(req.session.userId).exec(function (err, user) {
			if (err) return next(err);
			req.user = user;
			next();
		});
	} else {
		next();
	}
};

/**
 * Middleware to enable access to Keystone
 *
 * Bounces the user to the signin screen if they are not signed in or do not have permission.
 *
 * req.user is the user returned by the database. It's type is Keystone.List.
 *
 * req.user.canAccessKeystone denotes whether the user has access to the admin panel.
 * If you're having issues double check your user model. Setting `canAccessKeystone` to true in
 * the database will not be reflected here if it is virtual.
 * See http://mongoosejs.com/docs/guide.html#virtuals
 *
 * @param {Object} req - express request object
 * @param req.user - The user object Keystone.List
 * @param req.user.canAccessKeystone {Boolean|Function}
 * @param {Object} res - express response object
 * @param {function()} next callback
 */

exports.keystoneAuth = function (req, res, next) {
	if (!req.user || !req.user.canAccessKeystone) {
		if (req.headers.accept === 'application/json') {
			return req.user
				? res.status(403).json({ error: 'not authorised' })
				: res.status(401).json({ error: 'not signed in' });
		}
		var regex = new RegExp('^\/' + keystone.get('admin path') + '\/?$', 'i');
		var from = regex.test(req.originalUrl) ? '' : '?from=' + req.originalUrl;
		return res.redirect(keystone.get('signin url') + from);
	}
	next();
};
<commit_msg>Added "cookie signin options" option to keystone to allow customize all cookie options<commit_after>var crypto = require('crypto');
var keystone = require('../');
var scmp = require('scmp');
var utils = require('keystone-utils');
var _ = require('lodash');

/**
 * Creates a hash of str with Keystone's cookie secret.
 * Only hashes the first half of the string.
 */
function hash (str) {
	// force type
	str = '' + str;
	// get the first half
	str = str.substr(0, Math.round(str.length / 2));
	// hash using sha256
	return crypto
		.createHmac('sha256', keystone.get('cookie secret'))
		.update(str)
		.digest('base64')
		.replace(/\=+$/, '');
}

/**
 * Signs in a user using user obejct
 *
 * @param {Object} user - user object
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} onSuccess callback, is passed the User instance
 */

function signinWithUser (user, req, res, onSuccess) {
	if (arguments.length < 4) {
		throw new Error('keystone.session.signinWithUser requires user, req and res objects, and an onSuccess callback.');
	}
	if (typeof user !== 'object') {
		throw new Error('keystone.session.signinWithUser requires user to be an object.');
	}
	if (typeof req !== 'object') {
		throw new Error('keystone.session.signinWithUser requires req to be an object.');
	}
	if (typeof res !== 'object') {
		throw new Error('keystone.session.signinWithUser requires res to be an object.');
	}
	if (typeof onSuccess !== 'function') {
		throw new Error('keystone.session.signinWithUser requires onSuccess to be a function.');
	}
	req.session.regenerate(function () {
		req.user = user;
		req.session.userId = user.id;
		// if the user has a password set, store a persistence cookie to resume sessions
		if (keystone.get('cookie signin') && user.password) {
			var userToken = user.id + ':' + hash(user.password);
			var cookieOpts = _.defaults({
				signed: true,
				httpOnly: true,
				maxAge:  10 * 24 * 60 * 60
			}, keystone.get('cookie signin options'));
			res.cookie('keystone.uid', userToken, cookieOpts);
		}
		onSuccess(user);
	});
}

exports.signinWithUser = signinWithUser;

var postHookedSigninWithUser = function (user, req, res, onSuccess, onFail) {
	keystone.callHook(user, 'post:signin', function (err) {
		if (err) {
			return onFail(err);
		}
		exports.signinWithUser(user, req, res, onSuccess, onFail);
	});
};

/**
 * Signs in a user user matching the lookup filters
 *
 * @param {Object} lookup - must contain email and password
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} onSuccess callback, is passed the User instance
 * @param {function()} onFail callback
 */

var doSignin = function (lookup, req, res, onSuccess, onFail) {
	if (!lookup) {
		return onFail(new Error('session.signin requires a User ID or Object as the first argument'));
	}
	var User = keystone.list(keystone.get('user model'));
	if (typeof lookup.email === 'string' && typeof lookup.password === 'string') {
		// ensure that it is an email, we don't want people being able to sign in by just using "\." and a haphazardly correct password.
		if (!utils.isEmail(lookup.email)) {
			return onFail(new Error('Incorrect email or password'));
		}
		// create regex for email lookup with special characters escaped
		var emailRegExp = new RegExp('^' + utils.escapeRegExp(lookup.email) + '$', 'i');
		// match email address and password
		User.model.findOne({ email: emailRegExp }).exec(function (err, user) {
			if (user) {
				user._.password.compare(lookup.password, function (err, isMatch) {
					if (!err && isMatch) {
						postHookedSigninWithUser(user, req, res, onSuccess, onFail);
					} else {
						onFail(err || new Error('Incorrect email or password'));
					}
				});
			} else {
				onFail(err);
			}
		});
	} else {
		lookup = '' + lookup;
		// match the userId, with optional password check
		var userId = (lookup.indexOf(':') > 0) ? lookup.substr(0, lookup.indexOf(':')) : lookup;
		var passwordCheck = (lookup.indexOf(':') > 0) ? lookup.substr(lookup.indexOf(':') + 1) : false;
		User.model.findById(userId).exec(function (err, user) {
			if (user && (!passwordCheck || scmp(passwordCheck, hash(user.password)))) {
				postHookedSigninWithUser(user, req, res, onSuccess, onFail);
			} else {
				onFail(err || new Error('Incorrect user or password'));
			}
		});
	}
};

exports.signin = function (lookup, req, res, onSuccess, onFail) {
	keystone.callHook({}, 'pre:signin', function (err) {
		if (err) {
			return onFail(err);
		}
		doSignin(lookup, req, res, onSuccess, onFail);
	});
};

/**
 * Signs the current user out and resets the session
 *
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} next callback
 */

exports.signout = function (req, res, next) {
	keystone.callHook(req.user, 'pre:signout', function (err) {
		if (err) {
			console.log("An error occurred in signout 'pre' middleware", err);
		}
		var cookieOpts = _.defaults({
			signed: true,
			httpOnly: true,
			maxAge:  10 * 24 * 60 * 60
		}, keystone.get('cookie signin options'));
		res.clearCookie('keystone.uid', cookieOpts);
		req.user = null;
		req.session.regenerate(function (err) {
			if (err) {
				return next(err);
			}
			keystone.callHook({}, 'post:signout', function (err) {
				if (err) {
					console.log("An error occurred in signout 'post' middleware", err);
				}
				next();
			});
		});
	});
};

/**
 * Middleware to ensure session persistence across server restarts
 *
 * Looks for a userId cookie, and if present, and there is no user signed in,
 * automatically signs the user in.
 *
 * @param {Object} req - express request object
 * @param {Object} res - express response object
 * @param {function()} next callback
 */

exports.persist = function (req, res, next) {
	var User = keystone.list(keystone.get('user model'));
	if (!req.session) {
		console.error('\nKeystoneJS Runtime Error:\n\napp must have session middleware installed. Try adding "express-session" to your express instance.\n');
		process.exit(1);
	}
	if (keystone.get('cookie signin') && !req.session.userId && req.signedCookies['keystone.uid'] && req.signedCookies['keystone.uid'].indexOf(':') > 0) {
		exports.signin(req.signedCookies['keystone.uid'], req, res, function () {
			next();
		}, function (err) {
			var cookieOpts = _.defaults({
				signed: true,
				httpOnly: true,
				maxAge:  10 * 24 * 60 * 60
			}, keystone.get('cookie signin options'));
			res.clearCookie('keystone.uid', cookieOpts);
			req.user = null;
			next();
		});
	} else if (req.session.userId) {
		User.model.findById(req.session.userId).exec(function (err, user) {
			if (err) return next(err);
			req.user = user;
			next();
		});
	} else {
		next();
	}
};

/**
 * Middleware to enable access to Keystone
 *
 * Bounces the user to the signin screen if they are not signed in or do not have permission.
 *
 * req.user is the user returned by the database. It's type is Keystone.List.
 *
 * req.user.canAccessKeystone denotes whether the user has access to the admin panel.
 * If you're having issues double check your user model. Setting `canAccessKeystone` to true in
 * the database will not be reflected here if it is virtual.
 * See http://mongoosejs.com/docs/guide.html#virtuals
 *
 * @param {Object} req - express request object
 * @param req.user - The user object Keystone.List
 * @param req.user.canAccessKeystone {Boolean|Function}
 * @param {Object} res - express response object
 * @param {function()} next callback
 */

exports.keystoneAuth = function (req, res, next) {
	if (!req.user || !req.user.canAccessKeystone) {
		if (req.headers.accept === 'application/json') {
			return req.user
				? res.status(403).json({ error: 'not authorised' })
				: res.status(401).json({ error: 'not signed in' });
		}
		var regex = new RegExp('^\/' + keystone.get('admin path') + '\/?$', 'i');
		var from = regex.test(req.originalUrl) ? '' : '?from=' + req.originalUrl;
		return res.redirect(keystone.get('signin url') + from);
	}
	next();
};
<|endoftext|>


<commit_before>var RTMClient = require(__dirname + '/client'),
    open = require('open');

// TODO: Check validity of callback functions before using.

function RTMSession(options) {
    if (options == null) {
        options = {};
    }

    this.client = this.client || options.client || new RTMClient({
        apiKey: options.apiKey,
        secret: options.secret
    });

    this.token = this.token || options.token || null;
    this.timeline = this.timeline || options.timeline || null;
    this.frob = null;

    console.log('Options:', options);
}

RTMSession.prototype.makePrivRequest = function(method, options, callback) {
    return this.client.makePrivRequest(method, this.token, options, callback);
};

RTMSession.prototype.makeTimelineRequest = function(method, options, callback) {
    if (this.timeline == null) {
        this.createTimeline(function (err, timeline) {
            if (err) {
                callback(err, null);
                return;
            }

            this.timeline = timeline.timeline;
            this.makeTimelineRequest(method, options, callback);
        }.bind(this));
        return;
    }

    return this.client.makeTimelineRequest(method, this.token, this.timeline, options, callback);
};

RTMSession.prototype.login = function(callback) {
    if (this.token == null) {
        this.authenticate(callback);
        return;
    }

    this.client.checkToken(this.token, callback);
};

RTMSession.prototype.authenticate = function(callback) {
    process.stdin.resume();
    process.stdin.setEncoding('utf8');

    this.client.getFrob(function (err, frob) {
        this.client.getDesktopAuthURL(frob, 'delete', function (err, url) {
            if (err) {
                callback(err, null);
            }

            console.log('Once you have granted this application access to Remember the Milk, press any key to continue.');
            open(url);

            process.stdin.once('data', function (chunk) {
                process.stdin.pause();
                this.client.getToken(frob, function (err, token) {
                    if (err) {
                        callback(err, null);
                    }

                    this.token = token;
                    this.login(callback);
                }.bind(this));
            }.bind(this));
        }.bind(this));
    }.bind(this));
};

RTMSession.prototype.createTimeline = function(callback) {
    this.makePrivRequest('rtm.timelines.create', {}, callback);
};

RTMSession.prototype.undo = function(transactionID, callback) {
    this.makeTimelineRequest('rtm.transactions.undo', {
        transaction_id: transactionID
    }, callback);
};

RTMSession.prototype.addTask = function(name, callback) {
    this.makeTimelineRequest('rtm.tasks.add', {
        name: name,
        parse: 1
    }, function (err, data) {
        callback(err, data ? data.transaction.id : null);
    });
};

module.exports = RTMSession;
<commit_msg>Added the ability to get all lists.<commit_after>var RTMClient = require(__dirname + '/client'),
    open = require('open');

// TODO: Check validity of callback functions before using.

function RTMSession(options) {
    if (options == null) {
        options = {};
    }

    this.client = this.client || options.client || new RTMClient({
        apiKey: options.apiKey,
        secret: options.secret
    });

    this.token = this.token || options.token || null;
    this.timeline = this.timeline || options.timeline || null;
    this.frob = null;

    console.log('Options:', options);
}

RTMSession.prototype.makePrivRequest = function(method, options, callback) {
    return this.client.makePrivRequest(method, this.token, options, callback);
};

RTMSession.prototype.makeTimelineRequest = function(method, options, callback) {
    var self = this;

    if (self.timeline == null) {
        self.createTimeline(function (err, timeline) {
            if (err) {
                callback(err, null);
                return;
            }

            self.timeline = timeline.timeline;
            self.makeTimelineRequest(method, options, callback);
        });
        return;
    }

    return self.client.makeTimelineRequest(method, self.token, self.timeline, options, callback);
};

RTMSession.prototype.login = function(callback) {
    if (this.token == null) {
        this.authenticate(callback);
        return;
    }

    this.client.checkToken(this.token, callback);
};

RTMSession.prototype.authenticate = function(callback) {
    var self = this;

    process.stdin.resume();
    process.stdin.setEncoding('utf8');

    self.client.getFrob(function (err, frob) {
        self.client.getDesktopAuthURL(frob, 'delete', function (err, url) {
            if (err) {
                callback(err, null);
            }

            console.log('Once you have granted this application access to Remember the Milk, press any key to continue.');
            open(url);

            process.stdin.once('data', function (chunk) {
                process.stdin.pause();
                self.client.getToken(frob, function (err, token) {
                    if (err) {
                        callback(err, null);
                    }

                    self.token = token;
                    self.login(callback);
                });
            });
        });
    });
};

RTMSession.prototype.createTimeline = function(callback) {
    this.makePrivRequest('rtm.timelines.create', {}, callback);
};

RTMSession.prototype.undo = function(transactionID, callback) {
    this.makeTimelineRequest('rtm.transactions.undo', {
        transaction_id: transactionID
    }, callback);
};

RTMSession.prototype.addTask = function(name, callback) {
    this.makeTimelineRequest('rtm.tasks.add', {
        name: name,
        parse: 1
    }, function (err, data) {
        callback(err, data ? data.transaction.id : null);
    });
};

RTMSession.prototype.getLists = function(callback) {
    this.makePrivRequest('rtm.lists.getList', {}, function (err, data) {
        callback(err, data ? data.lists.list.filter(function (list) {
            return list.archived === '0' && list.deleted === '0';
        }) : null);
    });
};

module.exports = RTMSession;
<|endoftext|>


<commit_before>if (!process.env.VIPS_WARNING) process.env.VIPS_WARNING = "0";
var sharp = require('sharp');
var stream = require('stream');
var util = require('util');
var got = require('got');
var URL = require('url');
var MediaTyper = require('media-typer');
var XJ = require('xml-js');
var debug = require('debug')('sharpie');

var formats = (function(obj) {
	var map = {
		src: {},
		dst: {}
	};
	for (var format in obj) {
		if (obj[format].input.stream) map.src[format] = true;
		if (obj[format].output.stream) map.dst[format] = true;
	}
	return map;
})(sharp.format);

var ignoreHeaders = [
	"content-length",
	"connection",
	"keep-alive",
	"transfer-encoding",
	"upgrade",
	"server",
	"x-powered-by"
];

debug("Supported formats", formats);

module.exports = function(defaults) {
	defaults = Object.assign({
		rs: "w:2048,h:2048,max",
		q: 90,
		bg: false,
		flatten: false,
		param: 'url',
		format: false,
		hostnames: false,
		style: false,
		ratio: 'xMinYMin'
	}, defaults);
	defaults.signs = Object.assign({
		assignment: ':',
		separator: ','
	}, defaults.signs || {});

	return function(req, res, next) {
		var params = Object.assign({}, defaults, req.query);
		var url = req.params[defaults.param] || req.query[defaults.param];
		if (!url) return res.status(400).send("Missing url parameter");
		var resize = parseParams(defaults.signs, params.rs);
		var extract = parseParams(defaults.signs, params.ex);
		if (extract.x == null || extract.y == null || extract.w == null || extract.h == null) {
			extract = null;
		}
		var dstFormat = params.format;
		if (dstFormat && !(dstFormat in formats.dst)) {
			return res.type('text').status(400).send(`Unsupported image format ${dstFormat}`);
		}

		var urlObj = URL.parse(url);
		var curHost = req.get('Host');
		if (!urlObj.hostname) {
			url = URL.resolve(req.protocol + '://' + curHost + req.path, url);
		} else if (curHost != urlObj.hostname && !checkHostname(urlObj.hostname, defaults.hostnames)) {
			return res.status(403).send("Hostname not allowed: " + urlObj.hostname);
		}
		if (urlObj.protocol && urlObj.protocol != "http:" && urlObj.protocol != "https:") {
			return res.status(400).send("Unsupported protocol: " + urlObj.protocol);
		}
		debug("loading", url);

		var request = got.stream(url)
		.on('response', function(response) {
			var contentType = response.headers['content-type'];
			debug("got content type", contentType);
			var typeObj = MediaTyper.parse(contentType);
			if (typeObj.type != "image") {
				response.req.abort();
				return res.type('text').status(400).send(`Unexpected Content-Type ${contentType}`);
			}
			var srcFormat = typeObj.subtype;
			if (!dstFormat) {
				dstFormat = srcFormat;
			}

			Object.keys(response.headers).forEach(function(header) {
				if (ignoreHeaders.indexOf(header) >= 0) return;
				var nheader = header.split('-').map(function(s) {
					return s[0].toUpperCase() + s.substring(1);
				}).join('-');
				if (!res.get(nheader)) res.setHeader(nheader, response.headers[header]);
			});

			if (srcFormat in formats.src && dstFormat in formats.dst) {
				var formatOptions = {};
				if (params.q) {
					formatOptions.quality = parseInt(params.q);
				}

				res.setHeader('Content-Type', MediaTyper.format({
					type: 'image',
					subtype: dstFormat
				}));
				var pipeline = sharp();
				try {
					pipeline.metadata().then(function(meta) {
						var w = meta.width;
						var h = meta.height;
						if (extract) {
							var exOpts = normExtract(extract, w, h);
							w = exOpts.width;
							h = exOpts.height;
							debug("ex", exOpts);
							pipeline.extract(exOpts);
						}
						if (params.bg) {
							debug("bg", params.bg);
							pipeline.background(params.bg);
						}
						if (params.flatten) {
							debug("flatten", params.flatten);
							pipeline.flatten();
						}
						resize = normResize(resize, w, h);
						if (resize) {
							debug("resize", resize);
							pipeline.resize(resize.w, resize.h);
							if (!resize.enlarge) {
								debug("resize without enlargement");
								pipeline.withoutEnlargement();
							}
							if (params.crop) {
								debug("crop", params.crop);
								pipeline.crop(params.crop);
							}
							if (resize.max) {
								debug("max");
								pipeline.max();
							}
							if (resize.min) {
								debug("min");
								pipeline.min();
							}
						}
						return pipeline;
					}).then(function(pipeline) {
						pipeline.on('error', function(err) {
							res.type('text').status(500).send(`Response file error ${err.toString()}`);
						});
						pipeline.toFormat(dstFormat, formatOptions);
						pipeline.pipe(res);
					}).catch(next);
					request.pipe(pipeline);
				} catch(err) {
					return next(err);
				}
			} else {
				if (srcFormat == "svg" && dstFormat == "svg") {
					request.pipe(svgTransform(params, resize, extract)).pipe(res);
				} else {
					request.pipe(res);
				}
			}
		})
		.on('error', function(err) {
			err.status = err.statusCode;
			return next(err);
		});
	};
};

module.exports.sharp = sharp;

function parseParams(signs, str) {
	var obj = {};
	if (str) str.split(signs.separator).forEach(function(str) {
		var couple = str.trim().split(signs.assignment);
		var val = couple.length == 2 ? parseInt(couple[1]) : true;
		obj[couple[0]] = val;
	});
	return obj;
}

function normResize(resize, w, h) {
	if (!resize.w && !resize.h && !resize.z) {
		resize = null;
	} else if (resize.z) {
		// if one of the dimensions is set, don't set the other one
		var zw = Math.round((resize.w || w) * resize.z / 100);
		var zh = Math.round((resize.h || h) * resize.z / 100);
		if (resize.w == null && resize.h == null) {
			resize.w = zw;
			resize.h = zh;
		} else {
			if (resize.w != null) resize.w = zw;
			if (resize.h != null) resize.h = zh;
		}
	}
	return resize;
}

function normExtract(extract, w, h) {
	return {
		left: Math.min(Math.max(0, (extract.x - extract.w / 2) * w / 100), w),
		top: Math.min(Math.max(0, (extract.y - extract.h / 2) * h / 100), h),
		width: Math.max(Math.min(extract.w * w / 100, w), 0),
		height: Math.max(Math.min(extract.h * h / 100, h), 0)
	};
}

function checkHostname(hostname, opt) {
	var type = typeof opt;
	if (type == 'function') opt = opt(hostname);
	else if (Array.isArray(opt)) opt = ~opt.indexOf(hostname);
	else if (type == 'object') opt = opt[hostname];
	else if (type != 'boolean') throw new Error("Unhandled `hostnames` option type " + type);
	return !!opt;
}

function svgTransform(params, resize, extract) {
	var begun = false;
	var ended = false;
	var tagChunks = [];
	return new stream.Transform({transform: function(chunk, encoding, cb) {
		// this transform should work even if the start of the svg tag
		// is not in the same chunk as the end of the svg tag
		if (ended !== false) return cb(null, chunk);
		var start = 0;
		if (begun === false) {
			start = chunk.indexOf('<svg');
			if (start >= 0) {
				begun = start;
			}
		}
		if (begun !== false) {
			// if start of svg tag was found in previous chunk: 0; else `begun`
			var stop = chunk.indexOf('>', start);
			if (stop >= 0) {
				ended = true;
				var bufs = [chunk.slice(0, start), Buffer.from("<svg")];
				// get svg node as a string
				tagChunks.push(chunk.slice(start, stop + 1), Buffer.from("</svg>"));
				var xml = Buffer.concat(tagChunks).toString();
				var root;
				try {
					root = XJ.xml2js(xml, {compact: true});
				} catch(ex) {
					console.warn("Unparsable svg root", xml, ex.toString());
				}
				tagChunks = null;
				if (!root) return cb(null, chunk);
				var atts = root.svg._attributes;
				if (!atts.xmlns) atts.xmlns = "http://www.w3.org/2000/svg";
				var x = parseFloat(atts.x) || 0;
				var y = parseFloat(atts.y) || 0;
				delete atts.x;
				delete atts.y;
				var w = parseFloat(atts.width);
				var h = parseFloat(atts.height);
				if (atts.viewBox) {
					var viewBoxList = atts.viewBox.trim().split(' ');
					if (viewBoxList.length == 4) {
						x = parseFloat(viewBoxList[0]);
						y = parseFloat(viewBoxList[1]);
						w = parseFloat(viewBoxList[2]);
						h = parseFloat(viewBoxList[3]);
					}
				}

				if (extract) {
					extract = normExtract(extract, w, h);
					x += extract.left;
					y += extract.top;
					w = extract.width;
					h = extract.height;
				}
				if (!isNaN(x) && !isNaN(y) && !isNaN(w) && !isNaN(y)) {
					atts.viewBox = `${x} ${y} ${w} ${h}`;
				}
				if (params.ratio) {
					atts.preserveAspectRatio = params.ratio;
				} else if (atts.preserveAspectRatio == null) {
					atts.preserveAspectRatio = 'xMinYMin';
				}

				if (resize) {
					resize = normResize(resize, w, h);
					if ((resize.max && w > resize.w || resize.min && w < resize.w || resize.z)
					&& atts.viewBox) {
						atts.width = resize.w;
					} else {
						delete atts.width;
					}
					if ((resize.max && h > resize.h || resize.min && h < resize.h || resize.z)
					&& atts.viewBox) {
						atts.height = resize.h;
					} else {
						delete atts.height;
					}
				}
				var ordAtts = {
					xmlns: atts.xmlns,
					version: atts.version
				};
				delete atts.xmlns;
				delete atts.version;
				Object.assign(ordAtts, atts);
				for (var k in ordAtts) {
					if (ordAtts[k] != null) bufs.push(Buffer.from(` ${k}="${ordAtts[k]}"`));
				}
				bufs.push(chunk.slice(stop, stop + 1));
				if (params.style) {
					bufs.push(Buffer.from(svgStyle(params.style)));
				}
				bufs.push(chunk.slice(stop + 1));
				chunk = Buffer.concat(bufs);
			} else {
				tagChunks.push(chunk);
			}
		}
		cb(null, chunk);
	}});
}

function svgStyle(str) {
	return `<style type="text/css"><![CDATA[
${str}
]]></style>`;
}
<commit_msg>Check resize is null<commit_after>if (!process.env.VIPS_WARNING) process.env.VIPS_WARNING = "0";
var sharp = require('sharp');
var stream = require('stream');
var util = require('util');
var got = require('got');
var URL = require('url');
var MediaTyper = require('media-typer');
var XJ = require('xml-js');
var debug = require('debug')('sharpie');

var formats = (function(obj) {
	var map = {
		src: {},
		dst: {}
	};
	for (var format in obj) {
		if (obj[format].input.stream) map.src[format] = true;
		if (obj[format].output.stream) map.dst[format] = true;
	}
	return map;
})(sharp.format);

var ignoreHeaders = [
	"content-length",
	"connection",
	"keep-alive",
	"transfer-encoding",
	"upgrade",
	"server",
	"x-powered-by"
];

debug("Supported formats", formats);

module.exports = function(defaults) {
	defaults = Object.assign({
		rs: "w:2048,h:2048,max",
		q: 90,
		bg: false,
		flatten: false,
		param: 'url',
		format: false,
		hostnames: false,
		style: false,
		ratio: 'xMinYMin'
	}, defaults);
	defaults.signs = Object.assign({
		assignment: ':',
		separator: ','
	}, defaults.signs || {});

	return function(req, res, next) {
		var params = Object.assign({}, defaults, req.query);
		var url = req.params[defaults.param] || req.query[defaults.param];
		if (!url) return res.status(400).send("Missing url parameter");
		var resize = parseParams(defaults.signs, params.rs);
		var extract = parseParams(defaults.signs, params.ex);
		if (extract.x == null || extract.y == null || extract.w == null || extract.h == null) {
			extract = null;
		}
		var dstFormat = params.format;
		if (dstFormat && !(dstFormat in formats.dst)) {
			return res.type('text').status(400).send(`Unsupported image format ${dstFormat}`);
		}

		var urlObj = URL.parse(url);
		var curHost = req.get('Host');
		if (!urlObj.hostname) {
			url = URL.resolve(req.protocol + '://' + curHost + req.path, url);
		} else if (curHost != urlObj.hostname && !checkHostname(urlObj.hostname, defaults.hostnames)) {
			return res.status(403).send("Hostname not allowed: " + urlObj.hostname);
		}
		if (urlObj.protocol && urlObj.protocol != "http:" && urlObj.protocol != "https:") {
			return res.status(400).send("Unsupported protocol: " + urlObj.protocol);
		}
		debug("loading", url);

		var request = got.stream(url)
		.on('response', function(response) {
			var contentType = response.headers['content-type'];
			debug("got content type", contentType);
			var typeObj = MediaTyper.parse(contentType);
			if (typeObj.type != "image") {
				response.req.abort();
				return res.type('text').status(400).send(`Unexpected Content-Type ${contentType}`);
			}
			var srcFormat = typeObj.subtype;
			if (!dstFormat) {
				dstFormat = srcFormat;
			}

			Object.keys(response.headers).forEach(function(header) {
				if (ignoreHeaders.indexOf(header) >= 0) return;
				var nheader = header.split('-').map(function(s) {
					return s[0].toUpperCase() + s.substring(1);
				}).join('-');
				if (!res.get(nheader)) res.setHeader(nheader, response.headers[header]);
			});

			if (srcFormat in formats.src && dstFormat in formats.dst) {
				var formatOptions = {};
				if (params.q) {
					formatOptions.quality = parseInt(params.q);
				}

				res.setHeader('Content-Type', MediaTyper.format({
					type: 'image',
					subtype: dstFormat
				}));
				var pipeline = sharp();
				try {
					pipeline.metadata().then(function(meta) {
						var w = meta.width;
						var h = meta.height;
						if (extract) {
							var exOpts = normExtract(extract, w, h);
							w = exOpts.width;
							h = exOpts.height;
							debug("ex", exOpts);
							pipeline.extract(exOpts);
						}
						if (params.bg) {
							debug("bg", params.bg);
							pipeline.background(params.bg);
						}
						if (params.flatten) {
							debug("flatten", params.flatten);
							pipeline.flatten();
						}
						resize = normResize(resize, w, h);
						if (resize) {
							debug("resize", resize);
							pipeline.resize(resize.w, resize.h);
							if (!resize.enlarge) {
								debug("resize without enlargement");
								pipeline.withoutEnlargement();
							}
							if (params.crop) {
								debug("crop", params.crop);
								pipeline.crop(params.crop);
							}
							if (resize.max) {
								debug("max");
								pipeline.max();
							}
							if (resize.min) {
								debug("min");
								pipeline.min();
							}
						}
						return pipeline;
					}).then(function(pipeline) {
						pipeline.on('error', function(err) {
							res.type('text').status(500).send(`Response file error ${err.toString()}`);
						});
						pipeline.toFormat(dstFormat, formatOptions);
						pipeline.pipe(res);
					}).catch(next);
					request.pipe(pipeline);
				} catch(err) {
					return next(err);
				}
			} else {
				if (srcFormat == "svg" && dstFormat == "svg") {
					request.pipe(svgTransform(params, resize, extract)).pipe(res);
				} else {
					request.pipe(res);
				}
			}
		})
		.on('error', function(err) {
			err.status = err.statusCode;
			return next(err);
		});
	};
};

module.exports.sharp = sharp;

function parseParams(signs, str) {
	var obj = {};
	if (str) str.split(signs.separator).forEach(function(str) {
		var couple = str.trim().split(signs.assignment);
		var val = couple.length == 2 ? parseInt(couple[1]) : true;
		obj[couple[0]] = val;
	});
	return obj;
}

function normResize(resize, w, h) {
	if (!resize || !resize.w && !resize.h && !resize.z) {
		resize = null;
	} else if (resize.z) {
		// if one of the dimensions is set, don't set the other one
		var zw = Math.round((resize.w || w) * resize.z / 100);
		var zh = Math.round((resize.h || h) * resize.z / 100);
		if (resize.w == null && resize.h == null) {
			resize.w = zw;
			resize.h = zh;
		} else {
			if (resize.w != null) resize.w = zw;
			if (resize.h != null) resize.h = zh;
		}
	}
	return resize;
}

function normExtract(extract, w, h) {
	return {
		left: Math.min(Math.max(0, (extract.x - extract.w / 2) * w / 100), w),
		top: Math.min(Math.max(0, (extract.y - extract.h / 2) * h / 100), h),
		width: Math.max(Math.min(extract.w * w / 100, w), 0),
		height: Math.max(Math.min(extract.h * h / 100, h), 0)
	};
}

function checkHostname(hostname, opt) {
	var type = typeof opt;
	if (type == 'function') opt = opt(hostname);
	else if (Array.isArray(opt)) opt = ~opt.indexOf(hostname);
	else if (type == 'object') opt = opt[hostname];
	else if (type != 'boolean') throw new Error("Unhandled `hostnames` option type " + type);
	return !!opt;
}

function svgTransform(params, resize, extract) {
	var begun = false;
	var ended = false;
	var tagChunks = [];
	return new stream.Transform({transform: function(chunk, encoding, cb) {
		// this transform should work even if the start of the svg tag
		// is not in the same chunk as the end of the svg tag
		if (ended !== false) return cb(null, chunk);
		var start = 0;
		if (begun === false) {
			start = chunk.indexOf('<svg');
			if (start >= 0) {
				begun = start;
			}
		}
		if (begun !== false) {
			// if start of svg tag was found in previous chunk: 0; else `begun`
			var stop = chunk.indexOf('>', start);
			if (stop >= 0) {
				ended = true;
				var bufs = [chunk.slice(0, start), Buffer.from("<svg")];
				// get svg node as a string
				tagChunks.push(chunk.slice(start, stop + 1), Buffer.from("</svg>"));
				var xml = Buffer.concat(tagChunks).toString();
				var root;
				try {
					root = XJ.xml2js(xml, {compact: true});
				} catch(ex) {
					console.warn("Unparsable svg root", xml, ex.toString());
				}
				tagChunks = null;
				if (!root) return cb(null, chunk);
				var atts = root.svg._attributes;
				if (!atts.xmlns) atts.xmlns = "http://www.w3.org/2000/svg";
				var x = parseFloat(atts.x) || 0;
				var y = parseFloat(atts.y) || 0;
				delete atts.x;
				delete atts.y;
				var w = parseFloat(atts.width);
				var h = parseFloat(atts.height);
				if (atts.viewBox) {
					var viewBoxList = atts.viewBox.trim().split(' ');
					if (viewBoxList.length == 4) {
						x = parseFloat(viewBoxList[0]);
						y = parseFloat(viewBoxList[1]);
						w = parseFloat(viewBoxList[2]);
						h = parseFloat(viewBoxList[3]);
					}
				}

				if (extract) {
					extract = normExtract(extract, w, h);
					x += extract.left;
					y += extract.top;
					w = extract.width;
					h = extract.height;
				}
				if (!isNaN(x) && !isNaN(y) && !isNaN(w) && !isNaN(y)) {
					atts.viewBox = `${x} ${y} ${w} ${h}`;
				}
				if (params.ratio) {
					atts.preserveAspectRatio = params.ratio;
				} else if (atts.preserveAspectRatio == null) {
					atts.preserveAspectRatio = 'xMinYMin';
				}

				resize = normResize(resize, w, h);
				if (resize) {
					if ((resize.max && w > resize.w || resize.min && w < resize.w || resize.z)
					&& atts.viewBox) {
						atts.width = resize.w;
					} else {
						delete atts.width;
					}
					if ((resize.max && h > resize.h || resize.min && h < resize.h || resize.z)
					&& atts.viewBox) {
						atts.height = resize.h;
					} else {
						delete atts.height;
					}
				}
				var ordAtts = {
					xmlns: atts.xmlns,
					version: atts.version
				};
				delete atts.xmlns;
				delete atts.version;
				Object.assign(ordAtts, atts);
				for (var k in ordAtts) {
					if (ordAtts[k] != null) bufs.push(Buffer.from(` ${k}="${ordAtts[k]}"`));
				}
				bufs.push(chunk.slice(stop, stop + 1));
				if (params.style) {
					bufs.push(Buffer.from(svgStyle(params.style)));
				}
				bufs.push(chunk.slice(stop + 1));
				chunk = Buffer.concat(bufs);
			} else {
				tagChunks.push(chunk);
			}
		}
		cb(null, chunk);
	}});
}

function svgStyle(str) {
	return `<style type="text/css"><![CDATA[
${str}
]]></style>`;
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name           Google personal blocklist
// @namespace      curipha
// @description    Obscure annoying sites from search result
// @include        http://www.google.tld/search?*
// @include        https://www.google.tld/search?*
// @version        0.3.1
// @grant          none
// @noframes
// ==/UserScript==

(function(){
  'use strict';

  var block = [
    // General doorways
    'ceron.jp/', 'page2rss.com/', 'zenback.itmedia.co.jp/', 'hatebu-graph.com/',
    'b.hatena.ne.jp/',
    '[^/]+.s.hatena.ne.jp/',

    // Application doorways
    'www.altech-ads.com/', 'www.freewarelovers.com/', 'www.appbrain.com/',
    'download.cnet.com/',
    'www.vector.co.jp/soft/',
    '([^/]+.)?filehippo.com/',
    '(?!news)[^/]+.soft(onic|pedia).(com|jp)/', '[^/]+.uptodown.com/',

    // SNS doorways
    '([^/]+.)?favstar.fm/',
    '([^/]+.)?tw(ee|tr|i(?!tter))[^/.]+.[a-z]+/', // genocide...

    // Knowledge communities
    'questionbox.jp.msn.com/', 'ziddy.japan.zdnet.com/', 'soudan1.biglobe.ne.jp/', 'qanda.rakuten.ne.jp/',
    'www.itmedia.co.jp/qa/',
    'oshiete1?.(nifty.com|goo.ne.jp)/',
    '([^/]+.)?okwave.jp/', '([^/]+.)?chiebukuro(.travel)?.yahoo.co.jp/',

    // EC
    '(e?search|item).rakuten.co.jp/',
    '([^/]+.)?.animate-onlineshop.jp/',

    // Community
    'www.nicovideo.jp/',

    // Anime leakers
    'anime.dougasouko.com/',
    '([^/]+.)?anitube.se/',
    '([^/]*(anime|youtube)[^/]*|mvnavian).blog[0-9]*.(fc2.com|fc2blog.us)/',

    // Torrents
    '([^/]+.)?nyaa.se/',

    // Dll listing
    'systemexplorer.net/', '[^/]+.dll-files.com/',

    // Linux package listing
    'packages.(debian|ubuntu).org/',

    // Mirror
    'wpedia.goo.ne.jp/',

    // Mobile pages
    'www.amazon.co.jp/gp/aw/', 'mobile.twitter.com/'
  ];

  var opacity = 0.2;
  var pattern = new RegExp('^https?:\/\/(?:' + block.join('|').replace(/([.\/])/g, '\\$1') + ')', 'i');
  var googler = /^https?:\/\/www\.google\.com\/url\?/i;
  var t = 0;

  var blocker = function() {
    var result = document.getElementsByClassName('g');
    for (var li of result) {
      var a = li.querySelector('h3 > a[href]');
      if (!a) continue;

      if (googler.test(a.href)) {
        var alturi = li.querySelector('cite._Rm').textContent;
        if (typeof(alturi) !== 'string') continue;

        alturi = alturi.replace(/\s+\u203A\s+/g, '/');
        var uri = /^https?:\/\//.test(uri) ? alturi : 'http://' + alturi;
      }
      else {
        var uri = a.href;
      }

      if (pattern.test(uri)) li.style.opacity = opacity;
    }
  };
  var blocker_wrap = function() {
    if (t) return;
    t = setTimeout(function() {
      blocker();
      t = 0;
    }, 120);
  };

  blocker();

  var mo = new MutationObserver(blocker_wrap);
  mo.observe(document.body, { childList: true, subtree: true });
})();
<commit_msg>Update block list<commit_after>// ==UserScript==
// @name           Google personal blocklist
// @namespace      curipha
// @description    Obscure annoying sites from search result
// @include        http://www.google.tld/search?*
// @include        https://www.google.tld/search?*
// @version        0.3.1
// @grant          none
// @noframes
// ==/UserScript==

(function(){
  'use strict';

  var block = [
    // General doorways
    'ceron.jp/', 'page2rss.com/', 'zenback.itmedia.co.jp/', 'hatebu-graph.com/',
    'b.hatena.ne.jp/', 'web.kamel.io/',
    '[^/]+.s.hatena.ne.jp/',

    // Application doorways
    'www.altech-ads.com/', 'www.freewarelovers.com/', 'www.appbrain.com/',
    'download.cnet.com/',
    'www.vector.co.jp/soft/',
    '([^/]+.)?filehippo.com/',
    '(?!news)[^/]+.soft(onic|pedia).(com|jp)/', '[^/]+.uptodown.com/',

    // SNS doorways
    '([^/]+.)?favstar.fm/',
    '([^/]+.)?tw(ee|tr|i(?!tter))[^/.]+.[a-z]+/', // genocide...

    // Knowledge communities
    'questionbox.jp.msn.com/', 'ziddy.japan.zdnet.com/', 'soudan1.biglobe.ne.jp/', 'qanda.rakuten.ne.jp/',
    'www.itmedia.co.jp/qa/',
    'oshiete1?.(nifty.com|goo.ne.jp)/',
    '([^/]+.)?okwave.jp/', '([^/]+.)?chiebukuro(.travel)?.yahoo.co.jp/',

    // EC
    '(e?search|item).rakuten.co.jp/',
    '([^/]+.)?.animate-onlineshop.jp/',

    // Community
    'www.nicovideo.jp/',

    // Anime leakers
    'anime.dougasouko.com/',
    '([^/]+.)?anitube.se/',
    '([^/]*(anime|youtube)[^/]*|mvnavian).blog[0-9]*.(fc2.com|fc2blog.us)/',

    // Torrents
    '([^/]+.)?nyaa.se/',

    // Dll listing
    'systemexplorer.net/', '[^/]+.dll-files.com/',

    // Linux package listing
    'packages.(debian|ubuntu).org/',

    // Mirror
    'wpedia.goo.ne.jp/',

    // Mobile pages
    'www.amazon.co.jp/gp/aw/', 'mobile.twitter.com/'
  ];

  var opacity = 0.2;
  var pattern = new RegExp('^https?:\/\/(?:' + block.join('|').replace(/([.\/])/g, '\\$1') + ')', 'i');
  var googler = /^https?:\/\/www\.google\.com\/url\?/i;
  var t = 0;

  var blocker = function() {
    var result = document.getElementsByClassName('g');
    for (var li of result) {
      var a = li.querySelector('h3 > a[href]');
      if (!a) continue;

      if (googler.test(a.href)) {
        var alturi = li.querySelector('cite._Rm').textContent;
        if (typeof(alturi) !== 'string') continue;

        alturi = alturi.replace(/\s+\u203A\s+/g, '/');
        var uri = /^https?:\/\//.test(uri) ? alturi : 'http://' + alturi;
      }
      else {
        var uri = a.href;
      }

      if (pattern.test(uri)) li.style.opacity = opacity;
    }
  };
  var blocker_wrap = function() {
    if (t) return;
    t = setTimeout(function() {
      blocker();
      t = 0;
    }, 120);
  };

  blocker();

  var mo = new MutationObserver(blocker_wrap);
  mo.observe(document.body, { childList: true, subtree: true });
})();
<|endoftext|>