<commit_before>import Controller from '@ember/controller';
import {DEFAULT_QUERY_PARAMS} from 'ghost-admin/helpers/reset-query-params';
import {alias} from '@ember/object/computed';
import {computed} from '@ember/object';
import {get} from '@ember/object';
import {inject as service} from '@ember/service';

const TYPES = [{
    name: 'All posts',
    value: null
}, {
    name: 'Draft posts',
    value: 'draft'
}, {
    name: 'Published posts',
    value: 'published'
}, {
    name: 'Scheduled posts',
    value: 'scheduled'
}, {
    name: 'Featured posts',
    value: 'featured'
}];

const VISIBILITIES = [{
    name: 'All access',
    value: null
}, {
    name: 'Public',
    value: 'public'
}, {
    name: 'Members-only',
    value: 'members'
}, {
    name: 'Paid members-only',
    value: 'paid'
}];

const ORDERS = [{
    name: 'Newest',
    value: null
}, {
    name: 'Oldest',
    value: 'published_at asc'
}, {
    name: 'Recently updated',
    value: 'updated_at desc'
}];

export default Controller.extend({
    feature: service(),
    session: service(),
    store: service(),

    // default values for these are set in `init` and defined in `helpers/reset-query-params`
    queryParams: ['type', 'access', 'author', 'tag', 'order'],

    _hasLoadedTags: false,
    _hasLoadedAuthors: false,
    _hasLoadedSnippets: false,

    availableTypes: null,
    availableVisibilities: null,
    availableOrders: null,

    init() {
        this._super(...arguments);
        this.availableTypes = TYPES;
        this.availableOrders = ORDERS;
        this.availableVisibilities = VISIBILITIES;
        this.setProperties(DEFAULT_QUERY_PARAMS.posts);

        if (this.feature.get('emailAnalytics')) {
            this.availableOrders.push({
                name: 'Open rate',
                value: 'email.open_rate desc'
            });
        }
    },

    postsInfinityModel: alias('model'),

    showingAll: computed('type', 'author', 'tag', function () {
        let {type, author, tag, visibility} = this.getProperties(['type', 'visibility', 'author', 'tag']);

        return !type && !visibility && !author && !tag;
    }),

    selectedType: computed('type', function () {
        let types = this.get('availableTypes');
        return types.findBy('value', this.get('type')) || {value: '!unknown'};
    }),

    selectedVisibility: computed('visibility', function () {
        let visibilities = this.get('availableVisibilities');
        return visibilities.findBy('value', this.get('visibility')) || {value: '!unknown'};
    }),

    selectedOrder: computed('order', function () {
        let orders = this.get('availableOrders');
        return orders.findBy('value', this.get('order')) || {value: '!unknown'};
    }),

    _availableTags: computed(function () {
        return this.get('store').peekAll('tag');
    }),

    availableTags: computed('_availableTags.[]', function () {
        let tags = this.get('_availableTags')
            .filter(tag => tag.get('id') !== null)
            .sort((tagA, tagB) => tagA.name.localeCompare(tagB.name, undefined, {ignorePunctuation: true}));
        let options = tags.toArray();
        options.unshiftObject({name: 'All tags', slug: null});

        return options;
    }),

    selectedTag: computed('tag', '_availableTags.[]', function () {
        let tag = this.get('tag');
        let tags = this.get('availableTags');

        return tags.findBy('slug', tag) || {slug: '!unknown'};
    }),

    _availableAuthors: computed(function () {
        return this.get('store').peekAll('user');
    }),

    availableAuthors: computed('_availableAuthors.[]', function () {
        let authors = this.get('_availableAuthors');
        let options = authors.toArray();

        options.unshiftObject({name: 'All authors', slug: null});

        return options;
    }),

    selectedAuthor: computed('author', 'availableAuthors.[]', function () {
        let author = this.get('author');
        let authors = this.get('availableAuthors');

        return authors.findBy('slug', author) || {slug: '!unknown'};
    }),

    snippets: computed(function () {
        return this.store.peekAll('snippet');
    }),

    actions: {
        changeType(type) {
            this.set('type', get(type, 'value'));
        },

        changeVisibility(visibility) {
            this.set('visibility', get(visibility, 'value'));
        },

        changeAuthor(author) {
            this.set('author', get(author, 'slug'));
        },

        changeTag(tag) {
            this.set('tag', get(tag, 'slug'));
        },

        changeOrder(order) {
            this.set('order', get(order, 'value'));
        },

        openEditor(post) {
            this.transitionToRoute('editor.edit', 'post', post.get('id'));
        }
    }
});
<commit_msg>Fixed open rate appearing twice in posts ordering dropdown<commit_after>import Controller from '@ember/controller';
import {DEFAULT_QUERY_PARAMS} from 'ghost-admin/helpers/reset-query-params';
import {alias} from '@ember/object/computed';
import {computed} from '@ember/object';
import {get} from '@ember/object';
import {inject as service} from '@ember/service';

const TYPES = [{
    name: 'All posts',
    value: null
}, {
    name: 'Draft posts',
    value: 'draft'
}, {
    name: 'Published posts',
    value: 'published'
}, {
    name: 'Scheduled posts',
    value: 'scheduled'
}, {
    name: 'Featured posts',
    value: 'featured'
}];

const VISIBILITIES = [{
    name: 'All access',
    value: null
}, {
    name: 'Public',
    value: 'public'
}, {
    name: 'Members-only',
    value: 'members'
}, {
    name: 'Paid members-only',
    value: 'paid'
}];

const ORDERS = [{
    name: 'Newest',
    value: null
}, {
    name: 'Oldest',
    value: 'published_at asc'
}, {
    name: 'Recently updated',
    value: 'updated_at desc'
}];

export default Controller.extend({
    feature: service(),
    session: service(),
    store: service(),

    // default values for these are set in `init` and defined in `helpers/reset-query-params`
    queryParams: ['type', 'access', 'author', 'tag', 'order'],

    _hasLoadedTags: false,
    _hasLoadedAuthors: false,
    _hasLoadedSnippets: false,

    availableTypes: null,
    availableVisibilities: null,
    availableOrders: null,

    init() {
        this._super(...arguments);
        this.availableTypes = TYPES;
        this.availableOrders = ORDERS;
        this.availableVisibilities = VISIBILITIES;
        this.setProperties(DEFAULT_QUERY_PARAMS.posts);

        if (this.feature.get('emailAnalytics') && !this.availableOrders.findBy('name', 'Open rate')) {
            this.availableOrders.push({
                name: 'Open rate',
                value: 'email.open_rate desc'
            });
        }
    },

    postsInfinityModel: alias('model'),

    showingAll: computed('type', 'author', 'tag', function () {
        let {type, author, tag, visibility} = this.getProperties(['type', 'visibility', 'author', 'tag']);

        return !type && !visibility && !author && !tag;
    }),

    selectedType: computed('type', function () {
        let types = this.get('availableTypes');
        return types.findBy('value', this.get('type')) || {value: '!unknown'};
    }),

    selectedVisibility: computed('visibility', function () {
        let visibilities = this.get('availableVisibilities');
        return visibilities.findBy('value', this.get('visibility')) || {value: '!unknown'};
    }),

    selectedOrder: computed('order', function () {
        let orders = this.get('availableOrders');
        return orders.findBy('value', this.get('order')) || {value: '!unknown'};
    }),

    _availableTags: computed(function () {
        return this.get('store').peekAll('tag');
    }),

    availableTags: computed('_availableTags.[]', function () {
        let tags = this.get('_availableTags')
            .filter(tag => tag.get('id') !== null)
            .sort((tagA, tagB) => tagA.name.localeCompare(tagB.name, undefined, {ignorePunctuation: true}));
        let options = tags.toArray();
        options.unshiftObject({name: 'All tags', slug: null});

        return options;
    }),

    selectedTag: computed('tag', '_availableTags.[]', function () {
        let tag = this.get('tag');
        let tags = this.get('availableTags');

        return tags.findBy('slug', tag) || {slug: '!unknown'};
    }),

    _availableAuthors: computed(function () {
        return this.get('store').peekAll('user');
    }),

    availableAuthors: computed('_availableAuthors.[]', function () {
        let authors = this.get('_availableAuthors');
        let options = authors.toArray();

        options.unshiftObject({name: 'All authors', slug: null});

        return options;
    }),

    selectedAuthor: computed('author', 'availableAuthors.[]', function () {
        let author = this.get('author');
        let authors = this.get('availableAuthors');

        return authors.findBy('slug', author) || {slug: '!unknown'};
    }),

    snippets: computed(function () {
        return this.store.peekAll('snippet');
    }),

    actions: {
        changeType(type) {
            this.set('type', get(type, 'value'));
        },

        changeVisibility(visibility) {
            this.set('visibility', get(visibility, 'value'));
        },

        changeAuthor(author) {
            this.set('author', get(author, 'slug'));
        },

        changeTag(tag) {
            this.set('tag', get(tag, 'slug'));
        },

        changeOrder(order) {
            this.set('order', get(order, 'value'));
        },

        openEditor(post) {
            this.transitionToRoute('editor.edit', 'post', post.get('id'));
        }
    }
});
<|endoftext|>


<commit_before>/**
 * redir controller
 * redirects to external resources, while tracking the page view
 */

var config = require('../models/config.js');

var GITHUB_URL = 'https://github.com/openwhyd/openwhyd';
var FAQ_PAGE = GITHUB_URL + '/blob/master/docs/FAQ.md';
var SUPPORT_PAGE =
  GITHUB_URL + '/blob/master/docs/FAQ.md#how-to-contact-openwhyds-team';
var DONATE_PAGE = 'https://opencollective.com/openwhyd';
var PRIVACY_PAGE = config.urlPrefix + '/privacy';

var REDIRECTIONS = {
  '/about': [
    'https://medium.com/@adrienjoly/music-amongst-other-topics-a4f41657d6d',
    "Openwhyd's story"
  ],
  '/api': [GITHUB_URL + '/blob/master/docs/API.md', 'API Documentation'],
  '/community': [GITHUB_URL, 'Community'],
  '/contact': [SUPPORT_PAGE, 'Contact'],
  '/contribute': [
    FAQ_PAGE + '#id-love-to-contribute-to-openwhyd-how-can-i-help',
    'Contribute'
  ],
  '/donate': [DONATE_PAGE, 'Donate'],
  '/faq': [FAQ_PAGE, 'Frequently Asked Questions'],
  '/help': [SUPPORT_PAGE, 'Help'],
  '/sponsor': [DONATE_PAGE, 'Sponsor'],
  '/support': [SUPPORT_PAGE, 'Support'],
  '/team': [SUPPORT_PAGE, 'Team'],
  '/tos': [PRIVACY_PAGE, 'Terms of Service']
};

exports.controller = function(request, reqParams, response) {
  var path = request.url.split('?')[0];
  var [redirUrl, redirTitle] = REDIRECTIONS[path] || [];
  if (redirUrl) {
    response.redirectWithTracking(redirUrl, redirTitle);
  } else {
    response.notFound();
  }
};
<commit_msg>refacto: specify redirect titles in object + leaner redirection pages<commit_after>/**
 * redir controller
 * redirects to external resources, while tracking the page view
 */

var config = require('../models/config.js');

var GITHUB_URL = 'https://github.com/openwhyd/openwhyd';
var API_PAGE = 'https://openwhyd.github.io/openwhyd/API';
var FAQ_PAGE = 'https://openwhyd.github.io/openwhyd/FAQ';
var SUPPORT_PAGE = FAQ_PAGE + '#how-to-contact-openwhyds-team';
var DONATE_PAGE = 'https://opencollective.com/openwhyd';
var PRIVACY_PAGE = config.urlPrefix + '/privacy';

var REDIRECTIONS = {
  '/about': [
    'https://medium.com/@adrienjoly/music-amongst-other-topics-a4f41657d6d',
    { title: "Openwhyd's story" }
  ],
  '/api': [API_PAGE, { title: 'API Documentation' }],
  '/community': [GITHUB_URL, { title: 'Community' }],
  '/contact': [SUPPORT_PAGE, { title: 'Contact' }],
  '/contribute': [
    FAQ_PAGE + '#id-love-to-contribute-to-openwhyd-how-can-i-help',
    { title: 'Contribute' }
  ],
  '/donate': [DONATE_PAGE, { title: 'Donate' }],
  '/faq': [FAQ_PAGE, { title: 'Frequently Asked Questions' }],
  '/help': [SUPPORT_PAGE, { title: 'Help' }],
  '/sponsor': [DONATE_PAGE, { title: 'Sponsor' }],
  '/support': [SUPPORT_PAGE, { title: 'Support' }],
  '/team': [SUPPORT_PAGE, { title: 'Team' }],
  '/tos': [PRIVACY_PAGE, { title: 'Terms of Service' }]
};

exports.controller = function(request, reqParams, response) {
  var path = request.url.split('?')[0];
  var [redirUrl, { title } = {}] = REDIRECTIONS[path] || [];
  if (redirUrl) {
    response.redirectWithTracking(redirUrl, title);
  } else {
    response.notFound();
  }
};
<|endoftext|>


<commit_before><commit_msg>update model and vocabulary<commit_after><|endoftext|>


<commit_before>"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = require('@angular/core');
var http_1 = require('@angular/http');
require('rxjs/add/operator/map');
var CRUDService = (function () {
    function CRUDService(http) {
        this.http = http;
        console.log("CRUDService constructor.");
    }
    CRUDService.prototype.GetAllUser = function () {
        return this.http.get('https://jsonplaceholder.typicode.com/users')
            .map(function (response) { return response.json(); });
    };
    CRUDService = __decorate([
        core_1.Injectable(),
        __metadata('design:paramtypes', [http_1.Http])
    ], CRUDService);
    return CRUDService;
}());
exports.CRUDService = CRUDService;
//# sourceMappingURL=crud.service.js.map<commit_msg>Delete crud.service.js<commit_after><|endoftext|>


<commit_before>(function(angular) {
  "use strict";

  var app = angular.module('myApp.draftHub', ['firebase.auth', 'firebase', 'firebase.utils', 'ngRoute', 'angucomplete-alt', 'angularModalService', 'ui.bootstrap']);

  app.controller('DraftHubCtrl', ['$scope', 'fbutil', 'user', '$firebaseObject', 'FBURL', "$firebaseArray", '$modal', '$log', '$route', function($scope, fbutil, user, $firebaseObject, FBURL, $firebaseArray, $modal, $log, $route) {
    $scope.user = user;
    $scope.FBURL = FBURL;
    $scope.draftPosition;
    $scope.suggestedPlayers = [];
    $scope.watchList = [];
    $scope.round = 1;
    $scope.currentPick;
    $scope.begun = false;

    $scope.tabs = [{
      title: 'Dynamic Title 1',
      content: 'Dynamic content 1'
    }, {
      title: 'Dynamic Title 2',
      content: 'Dynamic content 2',
      disabled: true
    }];

    var playersRef = new Firebase(FBURL).child("players");
    var query = playersRef.orderByChild("adp").limitToFirst(500);
    var players = $firebaseArray(query);
    $scope.players = players;

    var draft = function($scope, draftPosition) {
      var suggestedPlayers = [];
      var draftPosition = draftPosition || parseInt($scope.draftPosition);
      var lookUntil;
      if (draftPosition + 20 < players.length) {
        lookUntil = draftPosition + 20;
      } else {
        lookUntil = players.length - 1;
      }
      for (var i = 0; i < players.length; i++) {
        if ((draftPosition - 2 <= players[i].adp) && (players[i].adp <= draftPosition + 3)) {
          suggestedPlayers.push(players[i]);
        }
        if (players[i].adp > draftPosition + 3) {
          break;
        }
      }
      $scope.suggestedPlayers = suggestedPlayers;
    }

    // -------------- Watch List ----------------------
    $scope.addToWL = function() {
      var selectedPlayer = $scope.selectedPlayer;
      $scope.watchList.push(selectedPlayer.originalObject);
      $scope.$broadcast('angucomplete-alt:clearInput');
    }
    $scope.removeFromWL = function(i) {
      $scope.watchList.splice(i, 1);
    }

    // --------------- Modal  ------------------------
    $scope.modal = $modal.open({
      templateUrl: 'myModalContent.html',
      backdrop: true,
      backdrop : 'static',
      keyboard :false,
      windowClass: 'modal',
      size: 'sm',
      controller: function($scope, $modalInstance, $log, draftPosition) {
        $scope.draftPosition = draftPosition;

        $scope.submit = function() {
          $log.log('Submiting user info.');
          $log.log($scope.draftPosition);
          draft($scope);
          var results = [$scope.suggestedPlayers, $scope.draftPosition];
          $modalInstance.close(results);
        }

        $scope.cancel = function() {
          $modalInstance.dismiss('cancel');
        };
      },
      resolve: {
        draftPosition: function() {
          return $scope.draftPosition;
        },
        suggestedPlayers: function() {
          return $scope.suggestedPlayers;
        }
      }
    });
    $scope.modal.result.then(function(results) {
      $scope.suggestedPlayers = results[0];
      $scope.draftPosition = results[1];
      $scope.currentPick = $scope.draftPosition;
      $scope.begun = true;
    }, function() {
      $log.info('Modal dismissed at: ' + new Date());
    });

    $scope.$on('$locationChangeStart', function(event) {
      $scope.modal.close();
    });

    $scope.nextRound = function() {
      $scope.round += 1;
      if ($scope.round % 2 == 0) {
        var nextPosition = (($scope.round - 1) * 32) + (32 - parseInt($scope.draftPosition)) + 1;
      } else {
        var nextPosition = (($scope.round - 1) * 32) + (parseInt($scope.draftPosition));
      }
      draft($scope, nextPosition);
      $scope.currentPick = nextPosition;
    }
    $scope.prevRound = function() {
      $scope.round -= 1;
      if ($scope.round % 2 == 0) {
        var prevPosition = (($scope.round - 1) * 32) + (32 - parseInt($scope.draftPosition)) + 1;
      } else {
        var prevPosition = (($scope.round - 1) * 32) + (parseInt($scope.draftPosition));
      }
      draft($scope, prevPosition);
      $scope.currentPick = prevPosition;
    }
    $scope.refresh = function() {
      $route.reload();
    }

    $scope.draftPlayer = function() {
        var draftedPlayer = $scope.draftedPlayer.originalObject;

        switch(draftedPlayer.pos){
            case 'QB':
                $scope.qb = draftedPlayer;
                break;
        }
    }
  }]);

  app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/draftHub', {
      templateUrl: 'draftHub/draftHub.html',
      controller: 'DraftHubCtrl',
      resolve: {
        // forces the page to wait for this promise to resolve before controller is loaded
        // the controller can then inject `user` as a dependency. This could also be done
        // in the controller, but this makes things cleaner (controller doesn't need to worry
        // about auth status or timing of accessing data or displaying elements)
        user: ['Auth', function(Auth) {
          return Auth.$waitForAuth();
        }]
      }
    });
  }]);

})(angular);
<commit_msg>clean up draftHub.js<commit_after>(function (angular) {
  "use strict";

  var app = angular.module('myApp.draftHub', ['firebase.auth', 'firebase', 'firebase.utils', 'ngRoute', 'angucomplete-alt', 'angularModalService', 'ui.bootstrap']);

  app.controller('DraftHubCtrl', ['$scope', 'fbutil', 'user', '$firebaseObject', 'FBURL', "$firebaseArray", '$modal', '$log', '$route', function ($scope, fbutil, user, $firebaseObject, FBURL, $firebaseArray, $modal, $log, $route) {
    // Firebase and User Inits
    $scope.user = user;
    $scope.FBURL = FBURL;

    $scope.draftPosition = null;
    $scope.currentPick = null;
    $scope.round = 1;

    $scope.suggestedPlayers = [];
    $scope.watchList = [];

    $scope.begun = false;

    var playersRef = new Firebase(FBURL).child("players");
    var query = playersRef.orderByChild("adp").limitToFirst(500);
    $scope.players = $firebaseArray(query);

    // --------------- Watch List ---------------
    $scope.addToWL = function () {
      $scope.watchList.push($scope.selectedPlayer.originalObject);
      $scope.$broadcast('angucomplete-alt:clearInput');
    };

    $scope.removeFromWL = function (i) {
      $scope.watchList.splice(i, 1);
    };

    // --------------- End of Watch List ---------------

    $scope.nextRound = function () {
      $scope.currentPick = getDraftPick($scope.round += 1);
      draft($scope, $scope.currentPick);
    };

    $scope.prevRound = function () {
      $scope.currentPick = getDraftPick($scope.round -= 1);
      draft($scope, $scope.currentPick);
    };

    $scope.refresh = function () {
      $route.reload();
    };

    // --------------- Modal  ---------------
    $scope.modal = $modal.open({
      templateUrl: 'myModalContent.html',
      backdrop: 'static',
      keyboard: false,
      windowClass: 'modal',
      size: 'sm',
      controller: function ($scope, $modalInstance, $log, draftPosition) {
        $scope.draftPosition = draftPosition;

        $scope.submit = function () {
          draft($scope);
          $modalInstance.close([$scope.suggestedPlayers, $scope.draftPosition]);
        };

        $scope.cancel = function () {
          $modalInstance.dismiss('cancel');
        };
      },
      resolve: {
        draftPosition: function () {
          return $scope.draftPosition;
        },
        suggestedPlayers: function () {
          return $scope.suggestedPlayers;
        }
      }
    });

    $scope.modal.result.then(function (results) {
      $scope.suggestedPlayers = results[0];
      $scope.draftPosition = results[1];
      $scope.currentPick = $scope.draftPosition;
      $scope.begun = true;
    }, function () {
      $log.info('Modal dismissed at: ' + new Date());
    });

    $scope.$on('$locationChangeStart', function (event) {
      $scope.modal.close();
    });

    // --------------- End of Modal  ---------------

    $scope.draftPlayer = function () {
      var draftedPlayer = $scope.draftedPlayer.originalObject;

      switch (draftedPlayer.pos) {
        case 'QB':
          $scope.qb = draftedPlayer;
          break;
      }
    };

    // Helpful Functions

    /**
    * Return the pick in the given round.
    * @function
    * @param {int} round - next or prev round.
    */
    function getDraftPick(round) {
      if (round % 2 === 0) {
        return ((round - 1) * 32) + (32 - parseInt($scope.draftPosition)) + 1;
      } else {
        return ((round - 1) * 32) + (parseInt($scope.draftPosition));
      }
    }

    function draft($scope, draftPos) {
      var suggestedPlayers = [],
          draftPosition = draftPos || parseInt($scope.draftPosition),
          lookUntil;

      if (draftPosition + 20 < $scope.players.length) {
        lookUntil = draftPosition + 20;
      } else {
        lookUntil = $scope.players.length - 1;
      }

      for (var i = 0; i < $scope.players.length; i++) {
        if ((draftPosition - 2 <= $scope.players[i].adp) && ($scope.players[i].adp <= draftPosition + 3)) {
          suggestedPlayers.push($scope.players[i]);
        }
        if ($scope.players[i].adp > draftPosition + 3) {
          break;
        }
      }
      $scope.suggestedPlayers = suggestedPlayers;
    }
  }]);

  app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/draftHub', {
      templateUrl: 'draftHub/draftHub.html',
      controller: 'DraftHubCtrl',
      resolve: {
        // forces the page to wait for this promise to resolve before controller is loaded
        // the controller can then inject `user` as a dependency. This could also be done
        // in the controller, but this makes things cleaner (controller doesn't need to worry
        // about auth status or timing of accessing data or displaying elements)
        user: ['Auth', function (Auth) {
          return Auth.$waitForAuth();
        }]
      }
    });
  }]);

})(angular);
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter
	, co = require('co')
	, Q = require('q')
	, config = require('../config.json');

function Scheduler(queue){
	var me = this;
	EventEmitter.call(this);

	this.doAJob = function (worker){
		return Q.Promise(function (resolve, reject){
			worker.on('completed', function (){
				resolve("ok");
			});

			worker.on('error', function (err){
				resolve("reject");
			});

			worker.work();
		});
	}

	this.run = function (){
		var parallel = 0;
		var worker = queue.next();

		var run_ = function (){
			while(worker && parallel < config.aggregation.parallel_jobs){

				(function (the_worker){
					parallel++;

					co(function *(){
						var state = yield me.doAJob(the_worker);
						if (state != "ok"){
							if (the_worker.getRetryTimes() < config.aggregation.max_retry_times){
								the_worker.addRetryTimes();
								queue.add(the_worker);
								me.emit('job', the_worker.getJob(), "retry");
							}
							else{
								me.emit('job', the_worker.getJob(), "drop")
							}
						}
						else{
							me.emit('job', the_worker.getJob(), "finish");
						}

						if (--parallel == 0){
							if (queue.size()){
								setImmediate(run_);
							}
							else{
								me.emit('completed');
							}
						}

						return;
					});

				})(worker);

				worker = queue.next();
			}
		}

		run_();
	}
}
require('util').inherits(Scheduler, EventEmitter);

module.exports = Scheduler;<commit_msg>	modified:   background/scheduler.js<commit_after>var EventEmitter = require('events').EventEmitter
	, co = require('co')
	, Q = require('q')
	, config = require('../config.json');

function Scheduler(queue){
	var me = this;
	EventEmitter.call(this);

	this.doAJob = function (worker){
		return Q.Promise(function (resolve, reject){
			worker.on('completed', function (){
				resolve("ok");
			});

			worker.on('error', function (err){
				resolve("reject");
			});

			worker.work();
		});
	}

	this.run = function (){
		if (!queue || !queue.size()){
			return me.emit('completed');
		}

		var parallel = 0;
		var worker = queue.next();

		var run_ = function (){
			while(worker && parallel < config.aggregation.parallel_jobs){

				(function (the_worker){
					parallel++;

					co(function *(){
						var state = yield me.doAJob(the_worker);
						if (state != "ok"){
							if (the_worker.getRetryTimes() < config.aggregation.max_retry_times){
								the_worker.addRetryTimes();
								queue.add(the_worker);
								me.emit('job', the_worker.getJob(), "retry");
							}
							else{
								me.emit('job', the_worker.getJob(), "drop")
							}
						}
						else{
							me.emit('job', the_worker.getJob(), "finish");
						}

						if (--parallel == 0){
							if (queue.size()){
								setImmediate(run_);
							}
							else{
								me.emit('completed');
							}
						}

						return;
					});

				})(worker);

				worker = queue.next();
			}
		}

		run_();
	}
}
require('util').inherits(Scheduler, EventEmitter);

module.exports = Scheduler;<|endoftext|>


<commit_before>/*jshint -W117, -W097 */
"use strict";

Package.describe({
  name: 'velocity:core',
  summary: 'Velocity, a Meteor specific test-runner',
  version: '0.2.0-pre0',
  git: 'https://github.com/xolvio/velocity.git'
});

Npm.depends({
  'chokidar': '0.8.2',
  'lodash': '2.4.1',
  'glob': '3.2.9',
  'rsync': '0.3.0',
  'fs-extra': '0.10.0',
  'freeport': '1.0.2'
});

Package.on_use(function (api) {
  if (api.versionsFrom) {
    api.versionsFrom('METEOR@0.9.0');
  }

  api.use('check');
  api.use('http');
  api.use('retry');

  api.add_files('collections.js', ['client', 'server']);

  api.export('Velocity', ['client', 'server']);
  api.export('VelocityTestFiles', ['client', 'server']);
  api.export('VelocityFixtureFiles', ['client', 'server']);
  api.export('VelocityTestReports', ['client', 'server']);
  api.export('VelocityAggregateReports', ['client', 'server']);
  api.export('VelocityLogs', ['client', 'server']);
  api.export('VelocityMirrors', ['client', 'server']);

  api.add_files('main.js', 'server');
  api.add_files(['lib/FileCopier.js'], 'server');
});
<commit_msg>Adds dependency to mongo-livedata for Meteor.Collection<commit_after>/*jshint -W117, -W097 */
"use strict";

Package.describe({
  name: 'velocity:core',
  summary: 'Velocity, a Meteor specific test-runner',
  version: '0.2.0-pre0',
  git: 'https://github.com/xolvio/velocity.git'
});

Npm.depends({
  'chokidar': '0.8.2',
  'lodash': '2.4.1',
  'glob': '3.2.9',
  'rsync': '0.3.0',
  'fs-extra': '0.10.0',
  'freeport': '1.0.2'
});

Package.on_use(function (api) {
  if (api.versionsFrom) {
    api.versionsFrom('METEOR@0.9.0');
    // This is required for Meteor.Collection since Meteor 0.9.1
    api.use('mongo-livedata');
  }

  api.use('check');
  api.use('http');
  api.use('retry');

  api.add_files('collections.js', ['client', 'server']);

  api.export('Velocity', ['client', 'server']);
  api.export('VelocityTestFiles', ['client', 'server']);
  api.export('VelocityFixtureFiles', ['client', 'server']);
  api.export('VelocityTestReports', ['client', 'server']);
  api.export('VelocityAggregateReports', ['client', 'server']);
  api.export('VelocityLogs', ['client', 'server']);
  api.export('VelocityMirrors', ['client', 'server']);

  api.add_files('main.js', 'server');
  api.add_files(['lib/FileCopier.js'], 'server');
});
<|endoftext|>


<commit_before>// Meteor package definition.
Package.describe({
  name: 'aramk:notifications',
  version: '0.2.0',
  summary: 'A notification widget.',
  git: 'https://github.com/aramk/meteor-notifications.git'
});

Package.onUse(function (api) {
  api.versionsFrom('METEOR@0.9.0');
  api.use([
    'coffeescript',
    'underscore',
    'templating',
    'less',
    'reactive-var@1.0.4',
    'tracker@1.0.5',
    'aramk:utility@0.8.6',
    'aldeed:simple-schema@1.3.2',
    'aldeed:collection2@2.3.3'
  ], 'client');
  api.use([
    'semantic:ui-css@1.11.5'
  ], {weak: true});
  api.imply('semantic:ui-css');
  api.export('Notifications', 'client');
  api.addFiles([
    'src/Notifications.coffee',
    'src/notification.html',
    'src/notification.coffee',
    'src/notificationBar.html',
    'src/notificationBar.coffee',
    'src/notificationBar.less'
  ], 'client');
});
<commit_msg>Update semantic-ui to v2<commit_after>// Meteor package definition.
Package.describe({
  name: 'aramk:notifications',
  version: '0.2.0',
  summary: 'A notification widget.',
  git: 'https://github.com/aramk/meteor-notifications.git'
});

Package.onUse(function (api) {
  api.versionsFrom('METEOR@0.9.0');
  api.use([
    'coffeescript',
    'underscore',
    'templating',
    'less',
    'reactive-var@1.0.4',
    'tracker@1.0.5',
    'aramk:utility@0.8.6',
    'aldeed:simple-schema@1.3.2',
    'aldeed:collection2@2.3.3'
  ], 'client');
  api.use([
    'semantic:ui-css@2.0.8'
  ], {weak: true});
  api.imply('semantic:ui-css');
  api.export('Notifications', 'client');
  api.addFiles([
    'src/Notifications.coffee',
    'src/notification.html',
    'src/notification.coffee',
    'src/notificationBar.html',
    'src/notificationBar.coffee',
    'src/notificationBar.less'
  ], 'client');
});
<|endoftext|>


<commit_before>// Import React
import React from "react";

// Import Spectacle Core tags
import {
  Appear,
  BlockQuote,
  Cite,
  CodePane,
  Deck,
  Fill,
  Heading,
  Image,
  Layout,
  Link,
  ListItem,
  List,
  Markdown,
  Quote,
  Slide,
  Spectacle,
  Text
} from "spectacle";

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

// Import custom component
import Interactive from "../assets/interactive";

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");

const images = {
  component: require("../assets/component.jpg"),
  ui1: require("../assets/ui1.jpg"),
  ui2: require("../assets/ui2.jpg"),
  wave: require("../assets/wave.png")
};

preloader(images);

const theme = createTheme({
  primary: "#0097A7"
});

export default class Presentation extends React.Component {
  render() {
    return (
      <Spectacle theme={theme}>
        <Deck transition={["zoom", "fade"]} transitionDuration={500}>

          <Slide transition={["zoom"]} bgColor="primary">
            <Heading size={1} fit caps lineHeight={1} textColor="black">
              Audius78
            </Heading>
            <Heading size={1} fit caps>
              A Collaborative Audio Editing Experience
            </Heading>
            <Heading size={1} fit caps textColor="black">
              Byron, Hieu, Keenan, & Patrick
            </Heading>
            <Link href="https://github.com/phuston/audius78">
              <Text bold caps textColor="tertiary">View on Github</Text>
            </Link>
          </Slide>

          <Slide transition={["fade"]} bgColor="tertiary">
            <Heading caps fit size={2} textColor="primary">
              Our Project
            </Heading>
            <Markdown>
              {`
###### We are aiming to build the world’s first cloud-based collaborative audio editor.
______
This entails a system where users can upload audio files, and then edit them together in ways like cutting, splicing, moving, as well as adding effects like fading and filtering.
              `}
            </Markdown>
          </Slide>

          <Slide transition={["zoom"]} bgColor="primary">
            <Heading caps fit size={2} textColor="black">
              Technologies
            </Heading>
            <Markdown>
              {`
* React with Redux
* Sockets
* Node & Express
* S3
* Webpack
* Custom WAVE parser thing
              `}
            </Markdown>
          </Slide>

          <Slide transition={["spin", "zoom"]} bgColor="tertiary">
            <Image width="100%" src={images.component}/>
          </Slide>

          <Slide transition={["slide", "spin"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              User Interface
            </Heading>
          </Slide>

          <Slide transition={[ "zoom"]} bgColor="primary">
            <Image width="100%" src={images.ui1}/>
          </Slide>

          <Slide transition={["zoom"]} bgColor="primary">
            <Image width="100%" src={images.ui2}/>
          </Slide>

          <Slide transition={["slide"]} bgColor="white">
            <Markdown>
              {`
#### Workflow
* Start a new workspace
* Upload a file (.wav, .mp3, etc.) to the server
* Client downloads .wav and displays it
* Operations are sent via the socket & applied locally
* All other clients in the network receive operation & update their files accordingly
* Server updates its locally cached files in order to remain synced with clients.
* Join an existing workspace
* Get .wav files from Amazon S3 instance given to client via socket by server
              `}
            </Markdown>
          </Slide>

          <Slide transition={["zoom", "fade"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              Storage of State
            </Heading>
            <CodePane
              lang="jsx"
              source={require("raw!../assets/state.example")}
              margin="20px auto"
            />
          </Slide>

          <Slide transition={["slide"]} bgColor="tertiary">
            <Markdown>
              {`
## Side-Project Audio Editor

* Handles both Node IO and Client-side IO
* Deals only with WAVE files
* Handles different operations using filters, including for our MVP
1. Splitting a file
2. Combining multiple files

##### Current state:
* Parsing WAVE files on Server-side
* Splitting WAVE files on Server-side
              `}
            </Markdown>
          </Slide>

          <Slide transition={["zoom"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              WAVE Files
            </Heading>
            <Image width="100%" src={images.wave}/>
          </Slide>

          <Slide transition={["fade"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              Our questions for you!
            </Heading>
          </Slide>

          <Slide transition={["fade"]} bgColor="secondary" textColor="primary">
            <List>
              <Appear><ListItem>Best way to save data on client side? e.g WAV files (~10mb per minute)
</ListItem></Appear>
              <Appear><ListItem>Does our architecture make sense? What improvements can we make?
</ListItem></Appear>
              <Appear><ListItem>Should we represent everything as text and do traditional OT?
</ListItem></Appear>
              <Appear><ListItem>Suggestions on client vs server side operations?
</ListItem></Appear>
              <Appear><ListItem>Suggestions of libraries or sources that can help us?
</ListItem></Appear>
            </List>
          </Slide>

        </Deck>
      </Spectacle>
    );
  }
}
<commit_msg>added slide<commit_after>// Import React
import React from "react";

// Import Spectacle Core tags
import {
  Appear,
  BlockQuote,
  Cite,
  CodePane,
  Deck,
  Fill,
  Heading,
  Image,
  Layout,
  Link,
  ListItem,
  List,
  Markdown,
  Quote,
  Slide,
  Spectacle,
  Text
} from "spectacle";

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

// Import custom component
import Interactive from "../assets/interactive";

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");

const images = {
  component: require("../assets/component.jpg"),
  ui1: require("../assets/ui1.jpg"),
  ui2: require("../assets/ui2.jpg"),
  wave: require("../assets/wave.png")
};

preloader(images);

const theme = createTheme({
  primary: "#0097A7"
});

export default class Presentation extends React.Component {
  render() {
    return (
      <Spectacle theme={theme}>
        <Deck transition={["zoom", "fade"]} transitionDuration={500}>

          <Slide transition={["zoom"]} bgColor="primary">
            <Heading size={1} fit caps lineHeight={1} textColor="black">
              Audius78
            </Heading>
            <Heading size={1} fit caps>
              A Collaborative Audio Editing Experience
            </Heading>
            <Heading size={1} fit caps textColor="black">
              Byron, Hieu, Keenan, & Patrick
            </Heading>
            <Link href="https://github.com/phuston/audius78">
              <Text bold caps textColor="tertiary">View on Github</Text>
            </Link>
          </Slide>

          <Slide transition={["fade"]} bgColor="tertiary">
            <Heading caps fit size={2} textColor="primary">
              Our Project
            </Heading>
            <Markdown>
              {`
###### We are aiming to build the world’s first cloud-based collaborative audio editor.
______
This entails a system where users can upload audio files, and then edit them together in ways like cutting, splicing, moving, as well as adding effects like fading and filtering.
              `}
            </Markdown>
          </Slide>

          <Slide transition={["zoom"]} bgColor="primary">
            <Heading caps fit size={2} textColor="black">
              Technologies
            </Heading>
            <Markdown>
              {`
* React with Redux
* Sockets
* Node & Express
* S3
* Webpack
* Custom WAVE parser thing
              `}
            </Markdown>
          </Slide>

          <Slide transition={["slide"]} bgColor="tertiary">
            <Heading caps fit size={2} textColor="black">
              Current Progress
            </Heading>
            <Markdown>
              {`
* Designed UI
* Set up webpack configuration
* Wrote .wav parser
* Learned Redux and structure architecture
* Figured out our client-to-server interactions
* Investigated audio visualization on front-end
              `}
            </Markdown>
          </Slide>

          <Slide transition={["spin", "zoom"]} bgColor="primary">
            <Image width="100%" src={images.component}/>
          </Slide>

          <Slide transition={["slide", "spin"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              User Interface
            </Heading>
          </Slide>

          <Slide transition={[ "zoom"]} bgColor="primary">
            <Image width="100%" src={images.ui1}/>
          </Slide>

          <Slide transition={["zoom"]} bgColor="primary">
            <Image width="100%" src={images.ui2}/>
          </Slide>

          <Slide transition={["slide"]} bgColor="white">
            <Markdown>
              {`
#### Workflow
* Start a new workspace
* Upload a file (.wav, .mp3, etc.) to the server
* Client downloads .wav and displays it
* Operations are sent via the socket & applied locally
* All other clients in the network receive operation & update their files accordingly
* Server updates its locally cached files in order to remain synced with clients.
* Join an existing workspace
* Get .wav files from Amazon S3 instance given to client via socket by server
              `}
            </Markdown>
          </Slide>

          <Slide transition={["zoom", "fade"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              Storage of State
            </Heading>
            <CodePane
              lang="jsx"
              source={require("raw!../assets/state.example")}
              margin="20px auto"
            />
          </Slide>

          <Slide transition={["slide"]} bgColor="tertiary">
            <Markdown>
              {`
## Side-Project Audio Editor

* Handles both Node IO and Client-side IO
* Deals only with WAVE files
* Handles different operations using filters, including for our MVP
1. Splitting a file
2. Combining multiple files

##### Current state:
* Parsing WAVE files on Server-side
* Splitting WAVE files on Server-side
              `}
            </Markdown>
          </Slide>

          <Slide transition={["zoom"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              WAVE Files
            </Heading>
            <Image width="100%" src={images.wave}/>
          </Slide>

          <Slide transition={["fade"]} bgColor="primary">
            <Heading caps fit size={1} textColor="tertiary">
              Our questions for you!
            </Heading>
          </Slide>

          <Slide transition={["fade"]} bgColor="secondary" textColor="primary">
            <List>
              <Appear><ListItem>Best way to save data on client side? e.g WAV files (~10mb per minute)
</ListItem></Appear>
              <Appear><ListItem>Does our architecture make sense? What improvements can we make?
</ListItem></Appear>
              <Appear><ListItem>Should we represent everything as text and do traditional OT?
</ListItem></Appear>
              <Appear><ListItem>Suggestions on client vs server side operations?
</ListItem></Appear>
              <Appear><ListItem>Suggestions of libraries or sources that can help us?
</ListItem></Appear>
            </List>
          </Slide>

        </Deck>
      </Spectacle>
    );
  }
}
<|endoftext|>


<commit_before>Package.describe({
  name: 'packaging:autopublish-test',
  summary: 'Dummy package to test auto-publish with TravisCI. DO NOT USE!',
  version: '0.0.7',
  git: 'https://github.com/MeteorPackaging/autopublish-test.git'
});

Package.onUse(function(api) {
  "use strict";

  api.versionsFrom('1.0.1');
  api.addFiles('lib/main.js');
});

Package.onTest(function(api) {
  "use strict";

  api.use('tinytest');
  api.use('packaging:autopublish-test');
  api.addFiles('tests/main.js');
});
<commit_msg>Bump to version 0.0.8<commit_after>Package.describe({
  name: 'packaging:autopublish-test',
  summary: 'Dummy package to test auto-publish with TravisCI. DO NOT USE!',
  version: '0.0.8',
  git: 'https://github.com/MeteorPackaging/autopublish-test.git'
});

Package.onUse(function(api) {
  "use strict";

  api.versionsFrom('1.0.1');
  api.addFiles('lib/main.js');
});

Package.onTest(function(api) {
  "use strict";

  api.use('tinytest');
  api.use('packaging:autopublish-test');
  api.addFiles('tests/main.js');
});
<|endoftext|>


<commit_before>Package.describe({
  name: 'oorabona:reactive-table',
  summary: 'Reactive tables with many options',
  version: '1.0.5',
  git: 'https://github.com/oorabona/reactive-table.git'
});

Package.onUse(function(api) {
  api.versionsFrom('1.0');

  // Made with Coffee
  api.use('coffeescript@1.0.1', 'client');

  // Core
  api.use('templating', 'client');
  api.use('jquery', 'client');
  api.use('underscore', 'client');
  api.use('reactive-var@1.0.3', 'client');

  api.addFiles([
    'reactive-table.html',
    'reactive-table.coffee'
  ], 'client');
});

Package.onTest(function(api) {
  api.use('tinytest');
  api.use('oorabona:reactive-table');
  api.addFiles('reactive-table-tests.coffee');
});
<commit_msg>Version bump.<commit_after>Package.describe({
  name: 'oorabona:reactive-table',
  summary: 'Reactive tables with many options',
  version: '1.0.6',
  git: 'https://github.com/oorabona/reactive-table.git'
});

Package.onUse(function(api) {
  api.versionsFrom('1.0');

  // Made with Coffee
  api.use('coffeescript@1.0.1', 'client');

  // Core
  api.use('templating', 'client');
  api.use('jquery', 'client');
  api.use('underscore', 'client');
  api.use('reactive-var@1.0.3', 'client');

  api.addFiles([
    'reactive-table.html',
    'reactive-table.coffee'
  ], 'client');
});

Package.onTest(function(api) {
  api.use('tinytest');
  api.use('oorabona:reactive-table');
  api.addFiles('reactive-table-tests.coffee');
});
<|endoftext|>


<commit_before>mol.modules.map.layers = function(mol) {

    mol.map.layers = {};

    mol.map.layers.LayerEngine = mol.mvp.Engine.extend(
        {
            init: function(proxy, bus, map) {
                this.proxy = proxy;
                this.bus = bus;
                this.map = map;
            },

            start: function() {
                this.display = new mol.map.layers.LayerListDisplay('.map_container');
                this.fireEvents();
                this.addEventHandlers();
				this.initSortable();
				this.display.toggle(false);
            },

            /**
             * Handler a layer-opacity event. This handler only does something
             * when the event.opacity is undefined. This is to support layer
             * toggling with opacity only (instead of removing overlays from
             * the map). In this case, the opacity from the layer widget is
             * bubbled to a new layer-opacity event that gets fired on the bus.
             */
            addEventHandlers: function() {
                var self = this;
                this.display.removeAll.click (
                    function(event) {

                        $(self.display).find(".close").trigger("click");
                    }
                );
                this.display.toggleAll.click (
                    function(event) {
                        _.each(
                            $(self.display).find(".toggle"),
                            function(checkbox){
                                    checkbox.click({currentTarget : this})
                            }
                        );
                    }
                );
                this.bus.addHandler(
                    'layer-opacity',
                    function(event) {
                        var layer = event.layer,
                            l = self.display.getLayer(layer),
                            opacity = event.opacity,
                            params = {},
                            e = null;

                        if (opacity === undefined) {
                            params = {
                                layer: layer,
                                opacity: parseFloat(l.find('.opacity').slider("value"))
                            },
                            e = new mol.bus.Event('layer-opacity', params);
                            self.bus.fireEvent(e);
                        }
                    }
                );

                this.bus.addHandler(
                    'add-layers',
                    function(event) {
                        _.each(
                            event.layers,
                            function(layer) { // Removes duplicate layers.
                                if (self.display.getLayer(layer).length > 0) {
                                    event.layers = _.without(event.layers, layer);
                                }
                            }
                        );
                        self.addLayers(event.layers);
                    }
                );
                this.bus.addHandler(
                    'layer-display-toggle',
                    function(event) {
                        var params = null,
                        e = null;

                        if (event.visible === undefined) {
                            self.display.toggle();
                            params = {visible: self.display.is(':visible')};
                        } else {
                            self.display.toggle(event.visible);
                        }
                    }
                );
            },

            /**
             * Fires the 'add-map-control' event. The mol.map.MapEngine handles
             * this event and adds the display to the map.
             */
            fireEvents: function() {
                var params = {
                        display: this.display,
                        slot: mol.map.ControlDisplay.Slot.TOP,
                        position: google.maps.ControlPosition.TOP_RIGHT
                    },
                    event = new mol.bus.Event('add-map-control', params);

                this.bus.fireEvent(event);
            },

            /**
             * Sorts layers so that they're grouped by name. Within each named
             * group, they are sorted by type: points, protectedarea, range,
             * ecoregion.
             *
             * @layers array of layer objects {name, type}
             */
            sortLayers: function(layers) {
                var sorted = [],
                    names_map = {};

                _.sortBy( // Layer names sorted alphabetically.
                    _.each(layers,
                          function(layer) {
                              names_map[layer.name] = layer.name; // Gather unique names.
                          })
                );

                _.each(_.keys(names_map),
                       function(name) {
                           var group = _.groupBy(_.groupBy(layers, "name")[name], "type");

                           _.each(
                               ['points', 'protectedarea', 'range', 'ecoregion'],
                               function(type) {
                                   if (group[type]) {
                                       sorted.push(group[type][0]);
                                   }
                               }
                           );
                       });

                return sorted;

            },

            /**
             * Handler for layer opacity changes via UI. It fires a layer-opacity
             * event on the bus, passing in the layer object and its opacity.
             */
            opacityHandler: function(layer, l) {
                return function(event) {
                    var params = {},
                        e = null;

                    l.toggle.attr('checked', true);

                    params = {
                        layer: layer,
                        opacity: parseFloat(l.opacity.slider("value"))
                    },

                    e = new mol.bus.Event('layer-opacity', params);

                    self.bus.fireEvent(e);
                };
            },

            /**
             * Adds layer widgets to the map. The layers parameter is an array
             * of layer objects {id, name, type, source}.
             */

            addLayers: function(layers) {
                var all = [],
                    layerIds = [],
                    sortedLayers = this.sortLayers(layers),
                    first = (this.display.find('.layer').length==0) ? true : false;

                _.each(
                    sortedLayers,
                    function(layer) {
                        var l = this.display.addLayer(layer),
                            self = this,
                            opacity = null;

                        self.bus.fireEvent(new mol.bus.Event('show-layer-display-toggle'));

                        // Set initial opacity based on layer type.
                        switch (layer.type) {
                        case 'points':
                            opacity = 1.0;
                            break;
                        case 'ecoregion':
                            opacity = .25;
                            break;
                        case 'protectedarea':
                            opacity = 1.0;
                            break;
                        case 'range':
                            opacity = .5;
                            break;
                        }

                        //disable interactivity to start
                        self.map.overlayMapTypes.forEach(
                                    function(mt) {
                                        mt.interaction.remove();
                                        mt.interaction.clickAction = "";
                                    }
                        );

                        // Hack so that at the end we can fire opacity event with all layers.
                        all.push({layer:layer, l:l, opacity:opacity});

                        // Opacity slider change handler.
                        l.opacity.bind("slide",self.opacityHandler(layer, l));
                        l.opacity.slider("value",opacity);

                        // Close handler for x button fires a 'remove-layers' event.
                        l.close.click(
                            function(event) {
                                var params = {
                                      layers: [layer]
                                    },
                                    e = new mol.bus.Event('remove-layers', params);

                                self.bus.fireEvent(e);
                                l.remove();
                                // Hide the layer widget toggle in the main menu if no layers exist
                                if(self.map.overlayMapTypes.length == 0) {
                                    self.bus.fireEvent(new mol.bus.Event('hide-layer-display-toggle'));
                                    self.display.toggle(false);
                                }
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );

                        // Click handler for zoom button fires 'layer-zoom-extent'
                        // and 'show-loading-indicator' events.
                        l.zoom.click(
                            function(event) {
                                var params = {
                                        layer: layer,
                                        auto_bound: true
                                    },
                                    e = new mol.bus.Event('layer-zoom-extent', params),
                                    le = new mol.bus.Event('show-loading-indicator',{source : "map"});

                                self.bus.fireEvent(e);
                                self.bus.fireEvent(le);
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.layer.click(
                            function(event) {
                                $(l.layer).focus();
                                if($(this).hasClass('selected')) {
                                    $(this).removeClass('selected');
                                } else {
                                    $(self.display).find('.selected').removeClass('selected');
                                    $(this).addClass('selected');
                                }

                                self.map.overlayMapTypes.forEach(
                                    function(mt) {
                                        if(mt.name == layer.id && $(l.layer).hasClass('selected')) {
                                            mt.interaction.add();
                                            mt.interaction.clickAction = "full"
                                        } else {
                                            mt.interaction.remove();
                                            mt.interaction.clickAction = "";
                                        }
                                    }
                                )
                                event.stopPropagation();
                                event.cancelBubble = true;

                            }
                        );

                        // Click handler for info button fires 'metadata-toggle'
                        l.info.click(
                            function(event) {
                                self.bus.fireEvent(new mol.bus.Event('metadata-toggle', {params : { layer: layer}}));
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.toggle.attr('checked', true);

                        // Click handler for the toggle button.
                        l.toggle.click(
                            function(event) {
                                var showing = $(event.currentTarget).is(':checked'),
                                    params = {
                                        layer: layer,
                                        showing: showing
                                    },
                                    e = new mol.bus.Event('layer-toggle', params);

                                self.bus.fireEvent(e);
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.source.click(
                            function(event) {
                                self.bus.fireEvent(new mol.bus.Event('metadata-toggle', {params : { provider: layer.source, type: layer.type, _class: layer._class, name: layer.name}}));
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.type.click(
                            function(event) {
                                self.bus.fireEvent(new mol.bus.Event('metadata-toggle', {params : { type: layer.type}}));
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        )
                        self.display.toggle(true);

                    },
                    this
                );

                // All of this stuff ensures layer orders are correct on map.
                layerIds = _.map(
                    sortedLayers,
                    function(layer) {
                        return layer.id;
                    },
                    this);
                this.bus.fireEvent(new mol.bus.Event('reorder-layers', {layers:layerIds}));

                // And this stuff ensures correct initial layer opacities on the map.
                _.each(
                    all.reverse(), // Reverse so that layers on top get rendered on top.
                    function(item) {
                        this.opacityHandler(item.layer, item.l)();
                    },
                    this
                );
                if(first) {
                    this.display.list.find('.layer')[0].click();
                }
            },

			   /**
			    * Add sorting capability to LayerListDisplay, when a result is
             * drag-n-drop, and the order of the result list is changed,
             * then the map will re-render according to the result list's order.
			    **/
			   initSortable: function() {
				    var self = this,
					     display = this.display;

				    display.list.sortable(
                    {
					        update: function(event, ui) {
						          var layers = [],
						          params = {},
                            e = null;

						          $(display.list).find('.layerContainer').each(
                                function(i, el) {
							               layers.push($(el).attr('id'));
						              }
                            );

                            params.layers = layers;
						          e = new mol.bus.Event('reorder-layers', params);
						          self.bus.fireEvent(e);
					         }
				        }
                    );

			   }
        }
    );

    mol.map.layers.LayerDisplay = mol.mvp.View.extend(
        {
            init: function(layer) {
                var html = '' +
                    '
' +
                    '
' +
                    '    <button class="source" title="Layer Source: {5}"></button>' +
                    '    <button class="type" title="Layer Type: {6}"></button>' +
                    '
' +
                    '
{4} features
' +
                    '
{2}
' +
                    '
{3}
' +
                    '
' +
                    '    <input class="keycatcher" type="text" />' +
                    '    <button title="Remove layer." class="close">x</button>' +
                    '    <button title="Zoom to layer extent." class="zoom">z</button>' +
                    //'    <button title="Layer metadata info." class="info">i</button>' +
                    '    <input class="toggle" type="checkbox">' +
                    '

' +
                    '
' +
                    '

' +
                    '
';

                this._super(html.format(layer.source, layer.type, layer.name, layer.names, layer.feature_count, layer.source_title, layer.type_title));
                this.attr('id', layer.id);
                this.opacity = $(this).find('.opacity').slider({value: 0.5, min: 0, max:1, step: 0.02, animate:"slow"});
                this.toggle = $(this).find('.toggle').button();
                this.zoom = $(this).find('.zoom');
                this.info = $(this).find('.info');
                this.close = $(this).find('.close');
                this.type = $(this).find('.type');
                this.source = $(this).find('.source');
                this.layer = $(this).find('.layer');
                this.keycatcher = $(this).find('.keycatcher');
                this.layerObj = layer;

            }
        }
    );

    mol.map.layers.LayerListDisplay = mol.mvp.View.extend(
        {
            init: function() {
                var html = '' +
                    '
' +
                    '
' +
                    '
' +
                    '           Layers ' +
                   /* '           none' +
                    '           all' +*/
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '           <button class="removeAll">Remove All Layers</button>' +
                    '           <button class="toggleAll">Toggle All Layers</button>' +
                    '
' +
                    '
' +
                    '
';

                this._super(html);
                this.list = $(this).find("#sortable");
                this.removeAll = $(this).find(".removeAll");
                this.toggleAll = $(this).find(".toggleAll");
                this.open = false;
                this.views = {};
                this.layers = [];

            },

            getLayer: function(layer) {
                return $(this).find('#{0}'.format(layer.id));
            },

			   getLayerById: function(id) {
				    return _.find(this.layers, function(layer){ return layer.id === id; });
			   },

            addLayer: function(layer) {
                var ld = new mol.map.layers.LayerDisplay(layer);
                this.list.append(ld);
				this.layers.push(layer);
                return ld;
            },

            render: function(howmany, order) {
				    var self = this;
                this.updateLayerNumber();
                return this;
            },

            updateLayerNumber: function() {
                var t = 0;
                _(this.layers).each(function(a) {
					if(a.enabled) t++;
				});
                $(this).find('.layer_number').html(t + " LAYER"+ (t>1?'S':''));
            },

            sortLayers: function() {
                var order = [];
                $(this).find('.layerContainer').each(function(i, el) {
					order.push($(el).attr('id'));
				});
                this.bus.emit("map:reorder_layers", order);
            },

            open: function(e) {
                if(e) e.preventDefault();
                this.el.addClass('open');
                this.el.css("z-index","100");
                this.open = true;
            },

            close: function(e) {
                this.el.removeClass('open');
                this.el.css("z-index","10");
                this.open = false;
            },

            sort_by: function(layers_order) {
                this.layers.sort(function(a, b) {
                                     return _(layers_order).indexOf(a.name) -
                                         _(layers_order).indexOf(b.name);
                                 });
                this.open = true;
                this.hiding();
            },

            hiding: function(e) {
                var layers = null;

                if (!this.open) {
                    return;
                }

                // put first what are showing
                this.layers.sort(
                    function(a, b) {
                        if (a.enabled && !b.enabled) {
                            return -1;
                        } else if (!a.enabled && b.enabled) {
                            return 1;
                        }
                        return 0;
                    }
                );
                layers = _(this.layers).pluck('name');
                this.bus.emit("map:reorder_layers", layers);
                this.order = layers;
                this.render(3);
                this.close();
            }
        }
    );
};
<commit_msg>Adding zoom to extent support to layer module.<commit_after>mol.modules.map.layers = function(mol) {

    mol.map.layers = {};

    mol.map.layers.LayerEngine = mol.mvp.Engine.extend(
        {
            init: function(proxy, bus, map) {
                this.proxy = proxy;
                this.bus = bus;
                this.map = map;
            },

            start: function() {
                this.display = new mol.map.layers.LayerListDisplay('.map_container');
                this.fireEvents();
                this.addEventHandlers();
                this.initSortable();
                this.display.toggle(false);
            },

            /**
             * Handler a layer-opacity event. This handler only does something
             * when the event.opacity is undefined. This is to support layer
             * toggling with opacity only (instead of removing overlays from
             * the map). In this case, the opacity from the layer widget is
             * bubbled to a new layer-opacity event that gets fired on the bus.
             */
            addEventHandlers: function() {
                var self = this;
                this.display.removeAll.click (
                    function(event) {

                        $(self.display).find(".close").trigger("click");
                    }
                );
                this.display.toggleAll.click (
                    function(event) {
                        _.each(
                            $(self.display).find(".toggle"),
                            function(checkbox){
                                    checkbox.click({currentTarget : this})
                            }
                        );
                    }
                );
                this.bus.addHandler(
                    'layer-opacity',
                    function(event) {
                        var layer = event.layer,
                            l = self.display.getLayer(layer),
                            opacity = event.opacity,
                            params = {},
                            e = null;

                        if (opacity === undefined) {
                            params = {
                                layer: layer,
                                opacity: parseFloat(l.find('.opacity').slider("value"))
                            },
                            e = new mol.bus.Event('layer-opacity', params);
                            self.bus.fireEvent(e);
                        }
                    }
                );

                this.bus.addHandler(
                    'add-layers',
                    function(event) {
                        var bounds = null;
                        _.each(
                            event.layers,
                            function(layer) { // Removes duplicate layers.
                                if (self.display.getLayer(layer).length > 0) {
                                    event.layers = _.without(event.layers, layer);
                                }
                            }
                        );
                        _.each(
                            event.layers,
                            function(layer) {
                                var extent = eval('({0})'.format(layer.extent));
                                var layer_bounds = new google.maps.LatLngBounds(
                                        new google.maps.LatLng(extent.sw.lat,extent.sw.lng),
                                        new google.maps.LatLng(extent.ne.lat,extent.ne.lng)
                                     );
                                if(!bounds) {
                                    bounds = layer_bounds;
                                } else {
                                    bounds.union(layer_bounds)
                                }
                            }
                        )
                        self.addLayers(event.layers);
                        self.map.fitBounds(bounds)

                    }
                );
                this.bus.addHandler(
                    'layer-display-toggle',
                    function(event) {
                        var params = null,
                        e = null;

                        if (event.visible === undefined) {
                            self.display.toggle();
                            params = {visible: self.display.is(':visible')};
                        } else {
                            self.display.toggle(event.visible);
                        }
                    }
                );
            },

            /**
             * Fires the 'add-map-control' event. The mol.map.MapEngine handles
             * this event and adds the display to the map.
             */
            fireEvents: function() {
                var params = {
                        display: this.display,
                        slot: mol.map.ControlDisplay.Slot.TOP,
                        position: google.maps.ControlPosition.TOP_RIGHT
                    },
                    event = new mol.bus.Event('add-map-control', params);

                this.bus.fireEvent(event);
            },

            /**
             * Sorts layers so that they're grouped by name. Within each named
             * group, they are sorted by type: points, protectedarea, range,
             * ecoregion.
             *
             * @layers array of layer objects {name, type}
             */
            sortLayers: function(layers) {
                var sorted = [],
                    names_map = {};

                _.sortBy( // Layer names sorted alphabetically.
                    _.each(layers,
                          function(layer) {
                              names_map[layer.name] = layer.name; // Gather unique names.
                          })
                );

                _.each(_.keys(names_map),
                       function(name) {
                           var group = _.groupBy(_.groupBy(layers, "name")[name], "type");

                           _.each(
                               ['points', 'protectedarea', 'range', 'ecoregion'],
                               function(type) {
                                   if (group[type]) {
                                       sorted.push(group[type][0]);
                                   }
                               }
                           );
                       });

                return sorted;

            },

            /**
             * Handler for layer opacity changes via UI. It fires a layer-opacity
             * event on the bus, passing in the layer object and its opacity.
             */
            opacityHandler: function(layer, l) {
                return function(event) {
                    var params = {},
                        e = null;

                    l.toggle.attr('checked', true);

                    params = {
                        layer: layer,
                        opacity: parseFloat(l.opacity.slider("value"))
                    },

                    e = new mol.bus.Event('layer-opacity', params);

                    self.bus.fireEvent(e);
                };
            },

            /**
             * Adds layer widgets to the map. The layers parameter is an array
             * of layer objects {id, name, type, source}.
             */

            addLayers: function(layers) {
                var all = [],
                    layerIds = [],
                    sortedLayers = this.sortLayers(layers),
                    first = (this.display.find('.layer').length==0) ? true : false;

                _.each(
                    sortedLayers,
                    function(layer) {
                        var l = this.display.addLayer(layer),
                            self = this,
                            opacity = null;

                        self.bus.fireEvent(new mol.bus.Event('show-layer-display-toggle'));

                        // Set initial opacity based on layer type.
                        switch (layer.type) {
                        case 'points':
                            opacity = 1.0;
                            break;
                        case 'ecoregion':
                            opacity = .25;
                            break;
                        case 'protectedarea':
                            opacity = 1.0;
                            break;
                        case 'range':
                            opacity = .5;
                            break;
                        }

                        //disable interactivity to start
                        self.map.overlayMapTypes.forEach(
                                    function(mt) {
                                        mt.interaction.remove();
                                        mt.interaction.clickAction = "";
                                    }
                        );

                        // Hack so that at the end we can fire opacity event with all layers.
                        all.push({layer:layer, l:l, opacity:opacity});

                        // Opacity slider change handler.
                        l.opacity.bind("slide",self.opacityHandler(layer, l));
                        l.opacity.slider("value",opacity);

                        // Close handler for x button fires a 'remove-layers' event.
                        l.close.click(
                            function(event) {
                                var params = {
                                      layers: [layer]
                                    },
                                    e = new mol.bus.Event('remove-layers', params);

                                self.bus.fireEvent(e);
                                l.remove();
                                // Hide the layer widget toggle in the main menu if no layers exist
                                if(self.map.overlayMapTypes.length == 0) {
                                    self.bus.fireEvent(new mol.bus.Event('hide-layer-display-toggle'));
                                    self.display.toggle(false);
                                }
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );

                        // Click handler for zoom button fires 'layer-zoom-extent'
                        // and 'show-loading-indicator' events.
                        l.zoom.click(
                            function(event) {
                                var params = {
                                        layer: layer,
                                        auto_bound: true
                                },
                                    extent = eval('({0})'.format(layer.extent)),
                                    bounds = new google.maps.LatLngBounds(new google.maps.LatLng(extent.sw.lat, extent.sw.lng), new google.maps.LatLng(extent.ne.lat, extent.ne.lng));
                                if(!$(l.layer).hasClass('selected')){
                                    l.layer.click();
                                }
                                self.map.fitBounds(bounds);

                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.layer.click(
                            function(event) {
                                $(l.layer).focus();
                                if($(this).hasClass('selected')) {
                                    $(this).removeClass('selected');
                                } else {
                                    $(self.display).find('.selected').removeClass('selected');
                                    $(this).addClass('selected');
                                }

                                self.map.overlayMapTypes.forEach(
                                    function(mt) {
                                        if(mt.name == layer.id && $(l.layer).hasClass('selected')) {
                                            mt.interaction.add();
                                            mt.interaction.clickAction = "full"
                                        } else {
                                            mt.interaction.remove();
                                            mt.interaction.clickAction = "";
                                        }
                                    }
                                )
                                event.stopPropagation();
                                event.cancelBubble = true;

                            }
                        );

                        // Click handler for info button fires 'metadata-toggle'
                        l.info.click(
                            function(event) {
                                self.bus.fireEvent(new mol.bus.Event('metadata-toggle', {params : { layer: layer}}));
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.toggle.attr('checked', true);

                        // Click handler for the toggle button.
                        l.toggle.click(
                            function(event) {
                                var showing = $(event.currentTarget).is(':checked'),
                                    params = {
                                        layer: layer,
                                        showing: showing
                                    },
                                    e = new mol.bus.Event('layer-toggle', params);

                                self.bus.fireEvent(e);
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.source.click(
                            function(event) {
                                self.bus.fireEvent(new mol.bus.Event('metadata-toggle', {params : { provider: layer.source, type: layer.type, _class: layer._class, name: layer.name}}));
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        );
                        l.type.click(
                            function(event) {
                                self.bus.fireEvent(new mol.bus.Event('metadata-toggle', {params : { type: layer.type}}));
                                event.stopPropagation();
                                event.cancelBubble = true;
                            }
                        )
                        self.display.toggle(true);

                    },
                    this
                );

                // All of this stuff ensures layer orders are correct on map.
                layerIds = _.map(
                    sortedLayers,
                    function(layer) {
                        return layer.id;
                    },
                    this);
                this.bus.fireEvent(new mol.bus.Event('reorder-layers', {layers:layerIds}));

                // And this stuff ensures correct initial layer opacities on the map.
                _.each(
                    all.reverse(), // Reverse so that layers on top get rendered on top.
                    function(item) {
                        this.opacityHandler(item.layer, item.l)();
                    },
                    this
                );
                if(first) {
                    this.display.list.find('.layer')[0].click();
                }
            },

               /**
                * Add sorting capability to LayerListDisplay, when a result is
             * drag-n-drop, and the order of the result list is changed,
             * then the map will re-render according to the result list's order.
                **/
               initSortable: function() {
                    var self = this,
                         display = this.display;

                    display.list.sortable(
                    {
                            update: function(event, ui) {
                                  var layers = [],
                                  params = {},
                            e = null;

                                  $(display.list).find('.layerContainer').each(
                                function(i, el) {
                                           layers.push($(el).attr('id'));
                                      }
                            );

                            params.layers = layers;
                                  e = new mol.bus.Event('reorder-layers', params);
                                  self.bus.fireEvent(e);
                             }
                        }
                    );

               }
        }
    );

    mol.map.layers.LayerDisplay = mol.mvp.View.extend(
        {
            init: function(layer) {
                var html = '' +
                    '
' +
                    '
' +
                    '    <button class="source" title="Layer Source: {5}"></button>' +
                    '    <button class="type" title="Layer Type: {6}"></button>' +
                    '
' +
                    '
{4} features
' +
                    '
{2}
' +
                    '
{3}
' +
                    '
' +
                    '    <input class="keycatcher" type="text" />' +
                    '    <button title="Remove layer." class="close">x</button>' +
                    '    <button title="Zoom to layer extent." class="zoom">z</button>' +
                    //'    <button title="Layer metadata info." class="info">i</button>' +
                    '    <input class="toggle" type="checkbox">' +
                    '

' +
                    '
' +
                    '

' +
                    '
';

                this._super(html.format(layer.source, layer.type, layer.name, layer.names, layer.feature_count, layer.source_title, layer.type_title));
                this.attr('id', layer.id);
                this.opacity = $(this).find('.opacity').slider({value: 0.5, min: 0, max:1, step: 0.02, animate:"slow"});
                this.toggle = $(this).find('.toggle').button();
                this.zoom = $(this).find('.zoom');
                this.info = $(this).find('.info');
                this.close = $(this).find('.close');
                this.type = $(this).find('.type');
                this.source = $(this).find('.source');
                this.layer = $(this).find('.layer');
                this.keycatcher = $(this).find('.keycatcher');
                this.layerObj = layer;

            }
        }
    );

    mol.map.layers.LayerListDisplay = mol.mvp.View.extend(
        {
            init: function() {
                var html = '' +
                    '
' +
                    '
' +
                    '
' +
                    '           Layers ' +
                   /* '           none' +
                    '           all' +*/
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '
' +
                    '           <button class="removeAll">Remove All Layers</button>' +
                    '           <button class="toggleAll">Toggle All Layers</button>' +
                    '
' +
                    '
' +
                    '
';

                this._super(html);
                this.list = $(this).find("#sortable");
                this.removeAll = $(this).find(".removeAll");
                this.toggleAll = $(this).find(".toggleAll");
                this.open = false;
                this.views = {};
                this.layers = [];

            },

            getLayer: function(layer) {
                return $(this).find('#{0}'.format(layer.id));
            },

               getLayerById: function(id) {
                    return _.find(this.layers, function(layer){ return layer.id === id; });
               },

            addLayer: function(layer) {
                var ld = new mol.map.layers.LayerDisplay(layer);
                this.list.append(ld);
                this.layers.push(layer);
                return ld;
            },

            render: function(howmany, order) {
                    var self = this;
                this.updateLayerNumber();
                return this;
            },

            updateLayerNumber: function() {
                var t = 0;
                _(this.layers).each(function(a) {
                    if(a.enabled) t++;
                });
                $(this).find('.layer_number').html(t + " LAYER"+ (t>1?'S':''));
            },

            sortLayers: function() {
                var order = [];
                $(this).find('.layerContainer').each(function(i, el) {
                    order.push($(el).attr('id'));
                });
                this.bus.emit("map:reorder_layers", order);
            },

            open: function(e) {
                if(e) e.preventDefault();
                this.el.addClass('open');
                this.el.css("z-index","100");
                this.open = true;
            },

            close: function(e) {
                this.el.removeClass('open');
                this.el.css("z-index","10");
                this.open = false;
            },

            sort_by: function(layers_order) {
                this.layers.sort(function(a, b) {
                                     return _(layers_order).indexOf(a.name) -
                                         _(layers_order).indexOf(b.name);
                                 });
                this.open = true;
                this.hiding();
            },

            hiding: function(e) {
                var layers = null;

                if (!this.open) {
                    return;
                }

                // put first what are showing
                this.layers.sort(
                    function(a, b) {
                        if (a.enabled && !b.enabled) {
                            return -1;
                        } else if (!a.enabled && b.enabled) {
                            return 1;
                        }
                        return 0;
                    }
                );
                layers = _(this.layers).pluck('name');
                this.bus.emit("map:reorder_layers", layers);
                this.order = layers;
                this.render(3);
                this.close();
            }
        }
    );
};
<|endoftext|>


<commit_before>Package.describe({
  name: "smowden:kissmetrics",
  summary: "Kissmetrics Smart package",
  version: "0.1.1",
  git: "https://github.com/smowden/meteor-kissmetrics.git"
});

Package.on_use(function (api) {
  api.versionsFrom("METEOR@0.9.0");
    api.use('tracker');
    api.use('accounts-base');
    api.use('underscore');
    api.add_files(['kissmetrics.js'], 'client');

    if (typeof api.export !== 'undefined') {
        api.export(['_kmq'], 'client');
    }
});<commit_msg>bugfixes<commit_after>Package.describe({
  name: "smowden:kissmetrics",
  summary: "Kissmetrics Smart package",
  version: "0.1.1",
  git: "https://github.com/smowden/meteor-kissmetrics.git"
});

Package.on_use(function (api) {
  api.versionsFrom("METEOR@0.9.0");
    api.use('tracker@1.0.0');
    api.use('accounts-base');
    api.use('underscore');
    api.add_files(['kissmetrics.js'], 'client');

    if (typeof api.export !== 'undefined') {
        api.export(['_kmq'], 'client');
    }
});<|endoftext|>