<commit_before>'use strict';
/*
 * VIP App
 *
 */
// Comment in if want to disable all "debug" logging
//debug.setLevel(0);

// VIP app module with its dependencies
var vipApp;
if(globalVars.isTesting)
  vipApp = angular.module('vipApp', ['ngTable', 'ngRoute', 'ngCookies', 'ngMockE2E']);
else
  vipApp = angular.module('vipApp', ['ngTable', 'ngRoute', 'ngCookies']);

// Constants
vipApp.constant('$appProperties', {
  contextRoot: '',
  servicesPath: '/services'
});

/*
 * VIP App configuration
 *
 * Will setup routing and retrieve reference data for the app before any pages are loaded
 *
 */
vipApp.config(['$routeProvider', '$appProperties', '$httpProvider',
  function ($routeProvider, $appProperties, $httpProvider) {

    $routeProvider.when('/', {
      templateUrl: $appProperties.contextRoot + '/app/partials/home.html',
      controller: 'HomeCtrl'
    });

    $routeProvider.when('/admin', {
      templateUrl: $appProperties.contextRoot + '/app/partials/admin.html',
      controller: 'AdminCtrl'
    });

    $routeProvider.when('/feeds', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feeds.html',
      controller: 'FeedsCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-overview.html',
      controller: 'FeedOverviewCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/source', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-source.html',
      controller: 'FeedSourceCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-election.html',
      controller: 'FeedElectionCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election/state', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-state.html',
      controller: 'FeedStateCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election/state/localities', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-localities.html',
      controller: 'FeedLocalitiesCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election/state/localities/:locality', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-locality.html',
      controller: 'FeedLocalityCtrl'
    });

    // done
    $routeProvider.when('/template/feed', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/feed.html'
    });
    // done
    $routeProvider.when('/template/source', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/source.html'
    });
    // done
    $routeProvider.when('/template/election', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/election.html'
    });
    // done
    $routeProvider.when('/template/state', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/state.html'
    });
    // done
    $routeProvider.when('/template/locality', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/locality.html'
    });

    $routeProvider.when('/template/precinct', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/precinct.html'
    });

    $routeProvider.when('/template/precinct-split', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/precinct-split.html'
    });

    $routeProvider.when('/template/election-administration', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/election-administration.html'
    });

    $routeProvider.when('/template/early-vote-site', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/early-vote-site.html'
    });

    $routeProvider.when('/template/polling-location', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/polling-location.html'
    });

    $routeProvider.when('/template/contests', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/contests.html'
    });

    $routeProvider.when('/template/contest', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/contest.html'
    });

    $routeProvider.when('/template/ballot', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/ballot.html'
    });

    $routeProvider.when('/template/candidate', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/candidate.html'
    });

    $routeProvider.when('/template/electoral-district', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/electoral-district.html'
    });

    $routeProvider.when('/template/contest-result', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/contest-result.html'
    });

    $routeProvider.when('/template/ballot-line-result', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/ballot-line-result.html'
    });

    $routeProvider.when('/template/results', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/results.html'
    });

    $routeProvider.when('/template/errors', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/errors.html'
    });

    $routeProvider.when('/template/search-results', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/search-results.html'
    });

    $routeProvider.when('/template/grid', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/grid.html'
    });

    $routeProvider.when('/profile', {
      templateUrl: $appProperties.contextRoot + '/app/partials/profile.html',
      controller: 'ProfileCtrl'
    });

    $routeProvider.when('/styleguide', {
      templateUrl: $appProperties.contextRoot + '/app/partials/styleguide.html',
      controller: 'StyleguideCtrl'
    });

    // default when no path specified
    $routeProvider.otherwise({redirectTo: '/'});

    /*
     * HTTP Interceptor
     * Will be used to check to see if user is authenticated
     */
    $httpProvider.responseInterceptors.push(function ($q, $location, $rootScope) {
      return function (promise) {
        return promise.then(
          // Success: just return the response
          function (response) {

            // if the user is logged in and going to the home page,
            // redirect to the feeds page
            if ($rootScope.user !== null && $rootScope.user.isAuthenticated === true && $location.path() === "/") {

              $location.url('/feeds');
            }

            return response;
          },
          // Error: check the error status for 401
          // and if so redirect back to homepage
          function (response) {
            if (response.status === 401) {
              // nullify the user object
              $rootScope.user = null;
              $location.url('/');
            }
            return $q.reject(response);
          });
      }
    });

  }
]);

/*
 * Static initialization block
 *
 */
vipApp.run(function ($rootScope, $appService, $location, $httpBackend, $appProperties, $window) {

  // TODO
  // initialize the cache for the app
  //$rootScope.cache = $cacheFactory('vipApp');
  InterceptorSetup($httpBackend, $appProperties);

  $rootScope.pageHeader = {};
  $rootScope.user = null;

  /*
   * Sets PageHeader values
   *
   * @param title - the Title of the page
   * @breadcrumbs - the breadcrumbs as an array
   * @section - section name used for the navigation bar "home", "admin", "feeds", "profile"
   * @error - error message to show on the screen
   * @error - alert message to show on the screen
   */
  $rootScope.setPageHeader = function (title, breadcrumbs, section, error, alert) {

    this.pageHeader.title = title;
    this.pageHeader.section = section;
    this.pageHeader.breadcrumbs = breadcrumbs;
    this.pageHeader.error = error;
    this.pageHeader.alert = alert;
  };

  // Before we render any pages,
  // see if user is authenticated or not and take appropriate action
  $appService.getUser()
    .success(function (data) {

      // set user object
      $rootScope.user = data;

      // redirect to home page if not authenticated
      if (data.isAuthenticated == false) {
        $location.path("/");
      }

    }).error(function (data) {

      // if we get an error, we could not connect to the server to check to
      // see if the user is authenticated, this should not happen
      $rootScope.pageHeader.error = "Server Error";
      $location.path("/");
    });

  // expose the $location into the scope
  $rootScope.$location = $location;

  // set a flag to determine if the screen is in mobile dimensions
  var mobileThreshhold = 1116;
  $rootScope.mobileDimensions = ($window.innerWidth < mobileThreshhold);
  $rootScope.toggleAside = true;
  window.onresize = function(){
    $rootScope.mobileDimensions = ($window.innerWidth < mobileThreshhold);
    if(!$rootScope.mobileDimensions){

      $rootScope.toggleAside = true;
    }
    $rootScope.$apply();
  }

  $rootScope.toggleAsideFunc = function(){
    if($rootScope.mobileDimensions){
      $rootScope.toggleAside = !$rootScope.toggleAside;
    }
  }

  $rootScope.createTableParams = function(ngTableParams, $filter, data, count, sorting) {
    // sets the defaults for the table sorting parameters
    return new ngTableParams({
      page: 1,
      count: count,
      sorting: sorting
    }, {
      total: data.length,
      // sets the type of sorting for the table
      getData: function ($defer, params) {
        var orderedData = params.sorting() ? $filter('orderBy')(data, params.orderBy()) : data;
        $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
      }
    });
  };

});
<commit_msg>disable the logProvider's debugging as Ngtable uses it and it crowds out all other logging without any other way to turn it off<commit_after>'use strict';
/*
 * VIP App
 *
 */
// Comment in if want to disable all "debug" logging
//debug.setLevel(0);

// VIP app module with its dependencies
var vipApp;
if(globalVars.isTesting)
  vipApp = angular.module('vipApp', ['ngTable', 'ngRoute', 'ngCookies', 'ngMockE2E']);
else
  vipApp = angular.module('vipApp', ['ngTable', 'ngRoute', 'ngCookies']);

// Constants
vipApp.constant('$appProperties', {
  contextRoot: '',
  servicesPath: '/services'
});

/*
 * VIP App configuration
 *
 * Will setup routing and retrieve reference data for the app before any pages are loaded
 *
 */
vipApp.config(['$routeProvider', '$appProperties', '$httpProvider', '$logProvider',
  function ($routeProvider, $appProperties, $httpProvider, $logProvider) {

    // disable the logProvider's debugging as Ngtable uses it and it crowds out all other logging
    // without any other way to turn it off
    $logProvider.debugEnabled(false);

    $routeProvider.when('/', {
      templateUrl: $appProperties.contextRoot + '/app/partials/home.html',
      controller: 'HomeCtrl'
    });

    $routeProvider.when('/admin', {
      templateUrl: $appProperties.contextRoot + '/app/partials/admin.html',
      controller: 'AdminCtrl'
    });

    $routeProvider.when('/feeds', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feeds.html',
      controller: 'FeedsCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-overview.html',
      controller: 'FeedOverviewCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/source', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-source.html',
      controller: 'FeedSourceCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-election.html',
      controller: 'FeedElectionCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election/state', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-state.html',
      controller: 'FeedStateCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election/state/localities', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-localities.html',
      controller: 'FeedLocalitiesCtrl'
    });

    $routeProvider.when('/feeds/:vipfeed/election/state/localities/:locality', {
      templateUrl: $appProperties.contextRoot + '/app/partials/feed-locality.html',
      controller: 'FeedLocalityCtrl'
    });

    // done
    $routeProvider.when('/template/feed', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/feed.html'
    });
    // done
    $routeProvider.when('/template/source', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/source.html'
    });
    // done
    $routeProvider.when('/template/election', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/election.html'
    });
    // done
    $routeProvider.when('/template/state', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/state.html'
    });
    // done
    $routeProvider.when('/template/locality', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/locality.html'
    });

    $routeProvider.when('/template/precinct', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/precinct.html'
    });

    $routeProvider.when('/template/precinct-split', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/precinct-split.html'
    });

    $routeProvider.when('/template/election-administration', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/election-administration.html'
    });

    $routeProvider.when('/template/early-vote-site', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/early-vote-site.html'
    });

    $routeProvider.when('/template/polling-location', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/polling-location.html'
    });

    $routeProvider.when('/template/contests', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/contests.html'
    });

    $routeProvider.when('/template/contest', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/contest.html'
    });

    $routeProvider.when('/template/ballot', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/ballot.html'
    });

    $routeProvider.when('/template/candidate', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/candidate.html'
    });

    $routeProvider.when('/template/electoral-district', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/electoral-district.html'
    });

    $routeProvider.when('/template/contest-result', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/contest-result.html'
    });

    $routeProvider.when('/template/ballot-line-result', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/ballot-line-result.html'
    });

    $routeProvider.when('/template/results', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/results.html'
    });

    $routeProvider.when('/template/errors', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/errors.html'
    });

    $routeProvider.when('/template/search-results', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/search-results.html'
    });

    $routeProvider.when('/template/grid', {
      templateUrl: $appProperties.contextRoot + '/app/partials/templates/grid.html'
    });

    $routeProvider.when('/profile', {
      templateUrl: $appProperties.contextRoot + '/app/partials/profile.html',
      controller: 'ProfileCtrl'
    });

    $routeProvider.when('/styleguide', {
      templateUrl: $appProperties.contextRoot + '/app/partials/styleguide.html',
      controller: 'StyleguideCtrl'
    });

    // default when no path specified
    $routeProvider.otherwise({redirectTo: '/'});

    /*
     * HTTP Interceptor
     * Will be used to check to see if user is authenticated
     */
    $httpProvider.responseInterceptors.push(function ($q, $location, $rootScope) {
      return function (promise) {
        return promise.then(
          // Success: just return the response
          function (response) {

            // if the user is logged in and going to the home page,
            // redirect to the feeds page
            if ($rootScope.user !== null && $rootScope.user.isAuthenticated === true && $location.path() === "/") {

              $location.url('/feeds');
            }

            return response;
          },
          // Error: check the error status for 401
          // and if so redirect back to homepage
          function (response) {
            if (response.status === 401) {
              // nullify the user object
              $rootScope.user = null;
              $location.url('/');
            }
            return $q.reject(response);
          });
      }
    });

  }
]);

/*
 * Static initialization block
 *
 */
vipApp.run(function ($rootScope, $appService, $location, $httpBackend, $appProperties, $window) {

  // TODO
  // initialize the cache for the app
  //$rootScope.cache = $cacheFactory('vipApp');
  InterceptorSetup($httpBackend, $appProperties);

  $rootScope.pageHeader = {};
  $rootScope.user = null;

  /*
   * Sets PageHeader values
   *
   * @param title - the Title of the page
   * @breadcrumbs - the breadcrumbs as an array
   * @section - section name used for the navigation bar "home", "admin", "feeds", "profile"
   * @error - error message to show on the screen
   * @error - alert message to show on the screen
   */
  $rootScope.setPageHeader = function (title, breadcrumbs, section, error, alert) {

    this.pageHeader.title = title;
    this.pageHeader.section = section;
    this.pageHeader.breadcrumbs = breadcrumbs;
    this.pageHeader.error = error;
    this.pageHeader.alert = alert;
  };

  // Before we render any pages,
  // see if user is authenticated or not and take appropriate action
  $appService.getUser()
    .success(function (data) {

      // set user object
      $rootScope.user = data;

      // redirect to home page if not authenticated
      if (data.isAuthenticated == false) {
        $location.path("/");
      }

    }).error(function (data) {

      // if we get an error, we could not connect to the server to check to
      // see if the user is authenticated, this should not happen
      $rootScope.pageHeader.error = "Server Error";
      $location.path("/");
    });

  // expose the $location into the scope
  $rootScope.$location = $location;

  // set a flag to determine if the screen is in mobile dimensions
  var mobileThreshhold = 1116;
  $rootScope.mobileDimensions = ($window.innerWidth < mobileThreshhold);
  $rootScope.toggleAside = true;
  window.onresize = function(){
    $rootScope.mobileDimensions = ($window.innerWidth < mobileThreshhold);
    if(!$rootScope.mobileDimensions){

      $rootScope.toggleAside = true;
    }
    $rootScope.$apply();
  }

  $rootScope.toggleAsideFunc = function(){
    if($rootScope.mobileDimensions){
      $rootScope.toggleAside = !$rootScope.toggleAside;
    }
  }

  $rootScope.createTableParams = function(ngTableParams, $filter, data, count, sorting) {
    // sets the defaults for the table sorting parameters
    return new ngTableParams({
      page: 1,
      count: count,
      sorting: sorting
    }, {
      total: data.length,
      // sets the type of sorting for the table
      getData: function ($defer, params) {
        var orderedData = params.sorting() ? $filter('orderBy')(data, params.orderBy()) : data;
        $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
      }
    });
  };

});
<|endoftext|>


<commit_before>var chai = require('chai');
var should = chai.should();
var expect = chai.expect;
var nock = require('nock');

var groups = require('./groups');
var errors = require('../errors');
var Cache = require('../cache');
var slackTypes = require('./types');

describe('groups', function () {

    before(function () {
        var cache = Cache;
        cache.data = {};
        cache.data.groups = [{ id: 'G0A1B2C3D4', name: 'private-group' }]
        cache.data.hostname = 'slack.com';
    });

    // function get(name, callback)
    describe('#getGroup', function () {

        it('should throw and error without a valid callback', function (done) {
            expect(function () {
                groups.getGroup(null, null);
            }).to.throw('callback must be a function');
            done();
        });

        it('should return an error to callback if missing required string argument', function (done) {

            groups.getGroup(null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });

        it('should return an error to callback when entity not found', function (done) {
            groups.getGroup('not_general', function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('the channel, group, or user could not be found');
            });
            done();
        });

        it('should return the group object from the cache', function (done) {
            groups.getGroup('private-group', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.id).to.equal('G0A1B2C3D4');
            });
            done();
        });
    });
    // function get(name, callback)
    describe('#getInfo', function () {

        it('should throw and error without a valid callback', function (done) {
            expect(function () {
                groups.getInfo(null);
            }).to.throw('callback must be a function');
            done();
        });

        it('should return an error to callback if missing required string argument', function (done) {

            groups.getInfo(null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });

        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.info')
                .reply(200, { ok: true });

            groups.getInfo('G0A1B2C34D', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
    });

    // function get(name, callback)
    describe('#getList', function () {

        it('should throw and error without a valid callback', function (done) {
            expect(function () {
                groups.getList(null);
            }).to.throw('callback must be a function');
            done();
        });

        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.list')
                .reply(200, { ok: true });

            groups.getList(function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
    });

    // function get(name, callback)
    describe('#mark', function () {

        it('should return an error to callback if missing required string argument', function (done) {

            groups.mark(null, null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });

        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.mark')
                .reply(200, { ok: true });

            groups.mark('G0A1B2C34D', 'timestamp', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
    });

    // function get(name, callback)
    describe('#setPurpose', function () {

        it('should return an error to callback if missing required string argument', function (done) {

            groups.setPurpose(null, null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });
        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.setPurpose')
                .reply(200, { ok: true });

            groups.setPurpose('G0A1B2C34D','purpose', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
    });

    // function get(name, callback)
    describe('#setTopic', function () {

        it('should return an error to callback if missing required string argument', function (done) {

            groups.setTopic(null, null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });
        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.setTopic')
                .reply(200, { ok: true });

            groups.setTopic('G0A1B2C34D','topic', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
    });

    after(function () {
        cache = null;
    });
});<commit_msg>Added test to group module<commit_after>var chai = require('chai');
var should = chai.should();
var expect = chai.expect;
var nock = require('nock');

var groups = require('./groups');
var errors = require('../errors');
var Cache = require('../cache');
var slackTypes = require('./types');

describe('groups', function () {

    before(function () {
        var cache = Cache;
        cache.data = {};
        cache.data.groups = [{ id: 'G0A1B2C3D4', name: 'private-group' }]
        cache.data.hostname = 'slack.com';
    });

    // function get(name, callback)
    describe('#getGroup', function () {

        it('should throw and error without a valid callback', function (done) {
            expect(function () {
                groups.getGroup(null, null);
            }).to.throw('callback must be a function');
            done();
        });

        it('should return an error to callback if missing required string argument', function (done) {

            groups.getGroup(null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });

        it('should return an error to callback when entity not found', function (done) {
            groups.getGroup('not_general', function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('the channel, group, or user could not be found');
            });
            done();
        });

        it('should return the group object from the cache', function (done) {
            groups.getGroup('private-group', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.id).to.equal('G0A1B2C3D4');
            });
            done();
        });
    });
    // function get(name, callback)
    describe('#getInfo', function () {

        it('should throw and error without a valid callback', function (done) {
            expect(function () {
                groups.getInfo(null);
            }).to.throw('callback must be a function');
            done();
        });

        it('should return an error to callback if missing required string argument', function (done) {

            groups.getInfo(null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });

        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.info')
                .reply(200, { ok: true });

            groups.getInfo('G0A1B2C34D', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });
        });
        it('should return an api error to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.info')
                .reply(200, { ok: false, error: 'group_not_found' });

            groups.getInfo('groupid', function (err, result) {
                expect(err).to.be.an('error');
                expect(err.message).to.equal('group_not_found');
                done();
            })
        });
    });

    // function get(name, callback)
    describe('#getList', function () {

        it('should throw and error without a valid callback', function (done) {
            expect(function () {
                groups.getList(null);
            }).to.throw('callback must be a function');
            done();
        });

        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.list')
                .reply(200, { ok: true });

            groups.getList(function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
        it('should return an api error to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.list')
                .reply(200, { ok: false, error: 'group_not_found' });

            groups.getList(function (err, result) {
                expect(err).to.be.an('error');
                expect(err.message).to.equal('group_not_found');
                done();
            })
        });
    });

    // function get(name, callback)
    describe('#mark', function () {

        it('should return an error to callback if missing required string argument', function (done) {

            groups.mark(null, null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });

        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.mark')
                .reply(200, { ok: true });

            groups.mark('G0A1B2C34D', 'timestamp', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
        it('should return an api error to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.mark')
                .reply(200, { ok: false, error: 'group_not_found' });

            groups.mark('groupid', 'timestamp',function (err, result) {
                expect(err).to.be.an('error');
                expect(err.message).to.equal('group_not_found');
                done();
            })
        });
    });

    // function get(name, callback)
    describe('#setPurpose', function () {

        it('should return an error to callback if missing required string argument', function (done) {

            groups.setPurpose(null, null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });
        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.setPurpose')
                .reply(200, { ok: true });

            groups.setPurpose('G0A1B2C34D','purpose', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
        it('should return an api error to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.setPurpose')
                .reply(200, { ok: false, error: 'group_not_found' });

            groups.setPurpose('groupid','purpose', function (err, result) {
                expect(err).to.be.an('error');
                expect(err.message).to.equal('group_not_found');
                done();
            })
        });
    });

    // function get(name, callback)
    describe('#setTopic', function () {

        it('should return an error to callback if missing required string argument', function (done) {

            groups.setTopic(null, null, function (err, result) {
                expect(err).to.not.equal(null);
                expect(err.message).to.equal('must supply valid argument(s)');
            });
            done();
        });
        it('should return an api response to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.setTopic')
                .reply(200, { ok: true });

            groups.setTopic('G0A1B2C34D','topic', function (err, result) {
                expect(result).to.be.an('object');
                expect(result.ok).to.equal(true);
                done();
            });

        });
        it('should return an api error to caller', function (done) {

            var scope = nock('https://slack.com')
                .post('/api/groups.setTopic')
                .reply(200, { ok: false, error: 'group_not_found' });

            groups.setTopic('groupid','topic', function (err, result) {
                expect(err).to.be.an('error');
                expect(err.message).to.equal('group_not_found');
                done();
            })
        });
    });
});<|endoftext|>


<commit_before>$(function()
{
	/*
	|--------------------------------------------------------------------------
	| Foundation scripts
	|--------------------------------------------------------------------------
	*/
	$(document).foundation();

	/*
	|--------------------------------------------------------------------------
	| Confirm dialog
	|--------------------------------------------------------------------------
	*/
	$(document).on('click', '.confirm', function()
	{
		var answer = confirm(confirm_question);
		if ( ! answer) return false;
	});

	/*
	|--------------------------------------------------------------------------
	| Select 2
	|--------------------------------------------------------------------------
	*/
	$('select').select2();

	/*
	|--------------------------------------------------------------------------
	| TinyMCE
	|--------------------------------------------------------------------------
	*/
	tinymce.init({
		selector           : 'textarea.wysi',
		theme              : 'modern',
		width              : '100%',
		menubar            : false,
		entity_encoding    : 'raw',
		plugins            : [
			"advlist anchor autolink autoresize charmap code contextmenu directionality emoticons",
			"fullscreen hr image insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak",
			"paste preview save searchreplace tabfocus table visualchars wordcount textcolor"
		],

		toolbar1 : "newdocument undo redo | cut copy paste removeformat | searchreplace | charmap emoticons | table | formatselect fontsizeselect | forecolor backcolor",
		toolbar2 : "bold italic underline strikethrough | hr | superscript subscript | bullist numlist | outdent indent blockquote | alignleft aligncenter alignright alignjustify | link unlink | image media | code fullscreen",

		setup : function(editor)
		{

		}
	});

})<commit_msg>Aggiornate toolbars TinyMCE<commit_after>$(function()
{
	/*
	|--------------------------------------------------------------------------
	| Foundation scripts
	|--------------------------------------------------------------------------
	*/
	$(document).foundation();

	/*
	|--------------------------------------------------------------------------
	| Confirm dialog
	|--------------------------------------------------------------------------
	*/
	$(document).on('click', '.confirm', function()
	{
		var answer = confirm(confirm_question);
		if ( ! answer) return false;
	});

	/*
	|--------------------------------------------------------------------------
	| Select 2
	|--------------------------------------------------------------------------
	*/
	$('select').select2();

	/*
	|--------------------------------------------------------------------------
	| TinyMCE
	|--------------------------------------------------------------------------
	*/
	tinymce.init({
		selector           : 'textarea.wysi',
		theme              : 'modern',
		width              : '100%',
		menubar            : false,
		entity_encoding    : 'raw',
		plugins            : [
			"advlist anchor autolink autoresize charmap code contextmenu directionality emoticons",
			"fullscreen hr image insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak",
			"paste preview save searchreplace tabfocus table visualchars wordcount textcolor"
		],

		toolbar1 : "newdocument undo redo | cut copy paste removeformat | searchreplace | charmap | table | formatselect | forecolor backcolor | code fullscreen",
		toolbar2 : "bold italic underline strikethrough | hr | superscript subscript blockquote | bullist numlist | alignleft aligncenter alignright alignjustify | link unlink | image media",

		setup : function(editor)
		{

		}
	});

})<|endoftext|>


<commit_before>/**
 * Created by sebastian.kaim on 26.04.2016.
 */
"use strict";

(function ($) {

    // dot helper class
    var dot = function (_x, _y, _text) {
        this.x = _x;
        this.y = _y;
        this.text = _text;
        this.radius = 16; // hover event radius

        this.render = function (context) {
            context.beginPath();
            context.arc(this.x, this.y, 4, 0, Math.PI * 2, true);
            context.fill();
        };
    };

    // register the plugin
    $.fn.dotHover = function (dots, options) {

        // settings
        var settings = $.extend({
            // defaults
            img: "karte.png", //$('#example.jpg').first(),
            dots: [],
            width: "100px",
            height: "100px",
            setmode: true,
            setcallback: function (dot) {}
        }, options );

        //
        // create tooltip canvas
        //
        var tooltip = $('<div/>')
            .appendTo('body')
            .addClass('hoverDotTooltip')
            .css({
                backgroundColor: 'white',
                border: '1px solid blue',
                position: 'absolute',
                padding: '5px',
                marginLeft: '-50px'
            })
            .hide();

        var contexts = [];

        var showHideTooltip = function (show) {
            if(show)
            {
                tooltip.show();
                tooltip.get(0).style.marginLeft = ((-tooltip.width() / 2) + 3) + "px";
            }
            else
            {
                tooltip.hide();
            }
        };

        //
        // handle tooltip positioning on mouse move
        //
        var mouseMoveEvent = function(event, img, offsetX, offsetY) {
            var mouseX = parseInt(event.clientX - offsetX);
            var mouseY = parseInt(event.clientY - offsetY);

            var hit = false;
            for (var i = 0; i < settings.dots.length; i++) {
                var dot = settings.dots[i];
                var dx = mouseX - dot.x;
                var dy = mouseY - dot.y;

                if (dx * dx + dy * dy < dot.radius) {
                    tooltip.get(0).style.top = (dot.y - 40) + "px";
                    tooltip.get(0).style.left = (dot.x) + "px";

                    tooltip.html(dot.text);
                    hit = true;
                }
            }

            showHideTooltip(hit);
        };

        // re-renders all dots
        var render = function () {
            $.each(contexts, function (i, ctx) {
                $.each(settings.dots, function (j, dot) {
                    dot.render(ctx);
                });
            });
        };

        //
        // places a new dot
        //
        var placedot = function (e) {
            var ndot = new dot(e.clientX  - 7, e.clientY - 7, "Example Text"); // -7,-7 for cursor offset

            settings.dots.push(ndot);
            render();
            settings.setcallback(ndot);
        };

        //
        // removes a dot
        //
        this.removeDot = function(x, y)
        {
            settings.dots = settings.dots.filter(function(el, index) {
                return dot.x == x && dot.y == y;
            });
        };

        // init mouse move on each element
        this.each(function(i, el) {
            el.style= 'background: url(' + settings.img + ');' +
            'background-repeat: no-repeat; ' +
            'background-size: contain;' +
            'width: ' + settings.width + '; ';
            //'height: ' + settings.height + '; '

            contexts.push(el.getContext('2d'));

            $(el).mousemove (function (event) {
                mouseMoveEvent(event, el, el.offsetLeft, el.offsetTop);
            });

            if(settings.setmode) $(el).click(placedot);
        });

        return this;
    };

})(jQuery);
<commit_msg>added dot construction<commit_after>/**
 * Copyright
 */
"use strict";

(function ($) {

    // dot helper class
    var dot = function (_x, _y, _text) {
        this.x = _x;
        this.y = _y;
        this.text = _text;
        this.radius = 16; // hover event radius

        this.render = function (context) {
            context.beginPath();
            context.arc(this.x, this.y, 4, 0, Math.PI * 2, true);
            context.fill();
        };
    };

    // register the plugin
    $.fn.dotHover = function (dots, options) {

        // settings
        var settings = $.extend({
            // defaults
            img: "karte.png", //$('#example.jpg').first(),
            width: "100px",
            height: "100px",
            setmode: true,
            setcallback: function (dot) {}
        }, options );

        // initialize dots
        settings.dots = [];
        $.each(dots, function (i, el) {
            settings.dots.push(new dot(el.x, el.y, el.text));
        });

        //
        // create tooltip canvas
        //
        var tooltip = $('<div/>')
            .appendTo('body')
            .addClass('hoverDotTooltip')
            .css({
                backgroundColor: 'white',
                border: '1px solid blue',
                position: 'absolute',
                padding: '5px',
                marginLeft: '-50px'
            })
            .hide();

        var contexts = [];

        var showHideTooltip = function (show) {
            if(show)
            {
                tooltip.show();
                tooltip.get(0).style.marginLeft = ((-tooltip.width() / 2) + 3) + "px";
            }
            else
            {
                tooltip.hide();
            }
        };

        //
        // handle tooltip positioning on mouse move
        //
        var mouseMoveEvent = function(event, img, offsetX, offsetY) {
            var mouseX = parseInt(event.clientX - offsetX);
            var mouseY = parseInt(event.clientY - offsetY);

            var hit = false;
            for (var i = 0; i < settings.dots.length; i++) {
                var dot = settings.dots[i];
                var dx = mouseX - dot.x;
                var dy = mouseY - dot.y;

                if (dx * dx + dy * dy < dot.radius) {
                    tooltip.get(0).style.top = (dot.y - 40) + "px";
                    tooltip.get(0).style.left = (dot.x) + "px";

                    tooltip.html(dot.text);
                    hit = true;
                }
            }

            showHideTooltip(hit);
        };

        // re-renders all dots
        var render = function () {
            $.each(contexts, function (i, ctx) {
                $.each(settings.dots, function (j, dot) {
                    dot.render(ctx);
                });
            });
        };

        //
        // places a new dot
        //
        var placedot = function (e) {
            var ndot = new dot(e.clientX  - 7, e.clientY - 7, "Example Text"); // -7,-7 for cursor offset

            settings.dots.push(ndot);
            render();
            settings.setcallback(ndot);
        };

        //
        // removes a dot
        //
        this.removeDot = function(x, y)
        {
            settings.dots = settings.dots.filter(function(el, index) {
                return dot.x == x && dot.y == y;
            });
        };

        // init mouse move on each element
        this.each(function(i, el) {
            el.style= 'background: url(' + settings.img + ');' +
            'background-repeat: no-repeat; ' +
            'background-size: contain;' +
            'width: ' + settings.width + '; ';
            //'height: ' + settings.height + '; '

            contexts.push(el.getContext('2d'));

            $(el).mousemove (function (event) {
                mouseMoveEvent(event, el, el.offsetLeft, el.offsetTop);
            });

            if(settings.setmode) $(el).click(placedot);
        });

        return this;
    };

})(jQuery);
<|endoftext|>


<commit_before>/*global describe:true, it:true */
"use strict";

var wd = require('wd')
  , assert = require('assert')
  , caps = {
      browserName: 'iOS'
      , platform: 'Mac'
      , version: '6.0'
    };

describe('get source', function() {
  var driver = wd.remote('127.0.0.1', 4723);
  return it('should return the page source', function(done) {
    driver.init(caps, function(err, sessionId) {
      driver.source(function(err, source){
        driver.quit(function() {
          assert.ok(~source.indexOf('UIAButton: "ComputeSumButton" NAME:"ComputeSumButton"'));
          done();
        });
      });
    });
  });
});
<commit_msg>ported source.js to use describeWd<commit_after>/*global it:true */
"use strict";

var describeWd = require('../helpers/driverblock.js').describe
  , assert = require('assert');

describeWd('get source', function(h) {
  return it('should return the page source', function(done) {
    h.driver.source(function(err, source){
      assert.ok(~source.indexOf('UIAButton: "ComputeSumButton" NAME:"ComputeSumButton"'));
      done();
    });
  });
});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import queryString from 'query-string';
import {
  stringifyRangeFilters,
  parseRangeFilters,
} from './profile-logic/range-filters';
import {
  stringifyTransforms,
  parseTransforms,
} from './profile-logic/transforms';
import { assertExhaustiveCheck, toValidTabSlug } from './utils/flow';
import { oneLine } from 'common-tags';
import type { UrlState } from './types/reducers';
import type { DataSource } from './types/actions';

export const CURRENT_URL_VERSION = 3;

function dataSourceDirs(urlState: UrlState) {
  const { dataSource } = urlState;
  switch (dataSource) {
    case 'from-addon':
      return ['from-addon'];
    case 'from-file':
      return ['from-file'];
    case 'local':
      return ['local', urlState.hash];
    case 'public':
      return ['public', urlState.hash];
    case 'from-url':
      return ['from-url', encodeURIComponent(urlState.profileUrl)];
    default:
      return [];
  }
}

// "null | void" in the query objects are flags which map to true for null, and false
// for void. False flags do not show up the URL.
type BaseQuery = {
  range?: string, //
  thread?: string, // "3"
  threadOrder?: string, // "3-2-0-1"
  hiddenThreads?: string | void, // "0-1"
  react_perf?: null, // Flag to activate react's UserTimings profiler.
  transforms?: string,
};

type CallTreeQuery = BaseQuery & {
  search?: string, // "js::RunScript"
  invertCallstack?: null | void,
  implementation?: string,
};

type MarkersQuery = BaseQuery & {
  markerSearch?: string, // "DOMEvent"
};

type StackChartQuery = BaseQuery & {
  search?: string, // "js::RunScript"
  invertCallstack?: null | void,
  implementation?: string,
};

type UrlObject = {
  pathParts: string[],
  query: Query,
};

type Query = BaseQuery | CallTreeQuery | MarkersQuery | StackChartQuery;

/**
 * Take the UrlState and map it into a serializable UrlObject, that represents the
 * target URL.
 */
export function urlStateToUrlObject(urlState: UrlState): UrlObject {
  const { dataSource } = urlState;
  if (dataSource === 'none') {
    return {
      pathParts: [],
      query: {},
    };
  }
  const pathParts = [...dataSourceDirs(urlState), urlState.selectedTab];

  // Start with the query parameters that are shown regardless of the active tab.
  const query: Object = {
    range: stringifyRangeFilters(urlState.rangeFilters) || undefined,
    thread: urlState.selectedThread,
    threadOrder: urlState.threadOrder.join('-'),
    file: urlState.pathInZipFile || undefined,
    v: CURRENT_URL_VERSION,
  };

  // Add the parameter hiddenThreads only when needed
  if (urlState.hiddenThreads.length > 0) {
    query.hiddenThreads = urlState.hiddenThreads.join('-');
  }

  if (process.env.NODE_ENV === 'development') {
    /* eslint-disable camelcase */
    query.react_perf = null;
    /* eslint-enable camelcase */
  }

  // Depending on which tab is active, also show tab-specific query parameters.
  const selectedTab = urlState.selectedTab;
  switch (selectedTab) {
    case 'stack-chart':
    case 'calltree': {
      query.search = urlState.callTreeSearchString || undefined;
      query.invertCallstack = urlState.invertCallstack ? null : undefined;
      query.implementation =
        urlState.implementation === 'combined'
          ? undefined
          : urlState.implementation;
      const selectedThread = urlState.selectedThread;
      if (selectedThread !== null) {
        query.transforms =
          stringifyTransforms(urlState.transforms[selectedThread]) || undefined;
      }
      break;
    }
    case 'marker-table':
      query.markerSearch = urlState.markersSearchString;
      break;
    case 'marker-chart':
    case 'flame-graph':
      break;
    default:
      assertExhaustiveCheck(selectedTab);
  }
  return { query, pathParts };
}

export function urlFromState(urlState: UrlState): string {
  const { pathParts, query } = urlStateToUrlObject(urlState);
  const { dataSource } = urlState;
  if (dataSource === 'none') {
    return '/';
  }
  const pathname =
    pathParts.length === 0 ? '/' : '/' + pathParts.join('/') + '/';

  const qString = queryString.stringify(query);
  return pathname + (qString ? '?' + qString : '');
}

function getDataSourceFromPathParts(pathParts: string[]): DataSource {
  const str = pathParts[0] || 'none';
  // With this switch, flow is able to understand that we return a valid value
  switch (str) {
    case 'none':
    case 'from-addon':
    case 'from-file':
    case 'local':
    case 'public':
    case 'from-url':
      return str;
    default:
      throw new Error(`Unexpected data source ${str}`);
  }
}

/**
 * Define only the properties of the window.location object that the function uses
 * so that it can be mocked in tests.
 */
type Location = {
  pathname: string,
  search: string,
  hash: string,
};

export function stateFromLocation(location: Location): UrlState {
  const { pathname, query } = upgradeLocationToCurrentVersion({
    pathname: location.pathname,
    hash: location.hash,
    query: queryString.parse(location.search.substr(1)),
  });

  const pathParts = pathname.split('/').filter(d => d);
  const dataSource = getDataSourceFromPathParts(pathParts);
  const selectedThread = query.thread !== undefined ? +query.thread : 0;

  // https://perf-html.io/public/{hash}/calltree/
  const hasProfileHash = ['local', 'public'].includes(dataSource);

  // https://perf-html.io/from-url/{url}/calltree/
  const hasProfileUrl = ['from-url'].includes(dataSource);

  // The selected tab is the last path part in the URL.
  const selectedTabPathPart = hasProfileHash || hasProfileUrl ? 2 : 1;

  let implementation = 'combined';
  // Don't trust the implementation values from the user. Make sure it conforms
  // to known values.
  if (query.implementation === 'js' || query.implementation === 'cpp') {
    implementation = query.implementation;
  }

  return {
    dataSource,
    hash: hasProfileHash ? pathParts[1] : '',
    profileUrl: hasProfileUrl ? decodeURIComponent(pathParts[1]) : '',
    selectedTab: toValidTabSlug(pathParts[selectedTabPathPart]) || 'calltree',
    rangeFilters: query.range ? parseRangeFilters(query.range) : [],
    selectedThread: selectedThread,
    callTreeSearchString: query.search || '',
    markersSearchString: query.markerSearch || '',
    implementation,
    invertCallstack: query.invertCallstack !== undefined,
    pathInZipFile: query.file || null,
    hiddenThreads: query.hiddenThreads
      ? query.hiddenThreads.split('-').map(index => Number(index))
      : [],
    threadOrder: query.threadOrder
      ? query.threadOrder.split('-').map(index => Number(index))
      : [],
    transforms: {
      [selectedThread]: query.transforms
        ? parseTransforms(query.transforms)
        : [],
    },
  };
}

type ProcessedLocation = { pathname: string, hash: string, query: Object };

export function upgradeLocationToCurrentVersion(
  processedLocation: ProcessedLocation
): ProcessedLocation {
  const urlVersion = +processedLocation.query.v || 0;
  if (urlVersion === CURRENT_URL_VERSION) {
    return processedLocation;
  }

  if (urlVersion > CURRENT_URL_VERSION) {
    throw new Error(
      `Unable to parse a url of version ${urlVersion} - are you running an outdated version of perf.html? ` +
        `The most recent version understood by this version of perf.html is version ${CURRENT_URL_VERSION}.\n` +
        'You can try refreshing this page in case perf.html has updated in the meantime.'
    );
  }
  // Convert to CURRENT_URL_VERSION, one step at a time.
  for (
    let destVersion = urlVersion;
    destVersion <= CURRENT_URL_VERSION;
    destVersion++
  ) {
    if (destVersion in _upgraders) {
      _upgraders[destVersion](processedLocation);
    }
  }

  processedLocation.query.v = CURRENT_URL_VERSION;
  return processedLocation;
}

// _upgraders[i] converts from version i - 1 to version i.
// Every "upgrader" takes the processedLocation as its single argument and mutates it.
/* eslint-disable no-useless-computed-key */
const _upgraders = {
  [0]: (processedLocation: ProcessedLocation) => {
    // Version 1 is the first versioned url.

    // If the pathname is '/', this could be a very old URL that has its information
    // stored in the hash.
    if (processedLocation.pathname === '/') {
      const legacyQuery = Object.assign(
        {},
        processedLocation.query,
        queryString.parse(processedLocation.hash)
      );
      if ('report' in legacyQuery) {
        // Put the report into the pathname.
        processedLocation.pathname = `/public/${legacyQuery.report}/calltree/`;
        processedLocation.hash = '';
        processedLocation.query = {};
      }
    }

    // Instead of implementation filters, we used to have jsOnly flags.
    if (processedLocation.query.jsOnly !== undefined) {
      // Support the old URL structure that had a jsOnly flag.
      delete processedLocation.query.jsOnly;
      processedLocation.query.implementation = 'js';
    }
  },
  [1]: (processedLocation: ProcessedLocation) => {
    // The transform stack was added. Convert the callTreeFilters into the new
    // transforms format.
    if (processedLocation.query.callTreeFilters) {
      // Before: "callTreeFilters=prefix-0KV4KV5KV61KV7KV8K~postfixjs-xFFpUMl"
      // After: "transforms=f-combined-0KV4KV5KV61KV7KV8K~f-js-xFFpUMl-i"
      processedLocation.query.transforms = processedLocation.query.callTreeFilters
        .split('~')
        .map(s => {
          const [type, val] = s.split('-');
          switch (type) {
            case 'prefix':
              return `f-combined-${val}`;
            case 'prefixjs':
              return `f-js-${val}`;
            case 'postfix':
              return `f-combined-${val}-i`;
            case 'postfixjs':
              return `f-js-${val}-i`;
            default:
              return undefined;
          }
        })
        .filter(f => f)
        .join('~');
      delete processedLocation.query.callTreeFilters;
    }
  },
  [2]: (processedLocation: ProcessedLocation) => {
    // Map the tab "timeline" to "stack-chart".
    // Map the tab "markers" to "marker-table".
    processedLocation.pathname = processedLocation.pathname
      // Given:    /public/e71ce9584da34298627fb66ac7f2f245ba5edbf5/timeline/
      // Matches:  $1^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      .replace(/^(\/[^/]+\/[^/]+)\/timeline\/?/, '$1/stack-chart/')
      // Given:    /public/e71ce9584da34298627fb66ac7f2f245ba5edbf5/markers/
      // Matches:  $1^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      .replace(/^(\/[^/]+\/[^/]+)\/markers\/?/, '$1/marker-table/');
  },
  [3]: (processedLocation: ProcessedLocation) => {
    const { query } = processedLocation;
    // Removed "Hide platform details" checkbox from the stack chart.
    if ('hidePlatformDetails' in query) {
      delete query.hidePlatformDetails;
      query.implementation = 'js';
    }
  },
};

if (Object.keys(_upgraders).length - 1 !== CURRENT_URL_VERSION) {
  throw new Error(oneLine`
    CURRENT_URL_VERSION does not match the number of URL upgraders. If you added a
    new upgrader, make sure and bump the CURRENT_URL_VERSION variable.
  `);
}
<commit_msg>Fix prettier<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import queryString from 'query-string';
import {
  stringifyRangeFilters,
  parseRangeFilters,
} from './profile-logic/range-filters';
import {
  stringifyTransforms,
  parseTransforms,
} from './profile-logic/transforms';
import { assertExhaustiveCheck, toValidTabSlug } from './utils/flow';
import { oneLine } from 'common-tags';
import type { UrlState } from './types/reducers';
import type { DataSource } from './types/actions';

export const CURRENT_URL_VERSION = 3;

function dataSourceDirs(urlState: UrlState) {
  const { dataSource } = urlState;
  switch (dataSource) {
    case 'from-addon':
      return ['from-addon'];
    case 'from-file':
      return ['from-file'];
    case 'local':
      return ['local', urlState.hash];
    case 'public':
      return ['public', urlState.hash];
    case 'from-url':
      return ['from-url', encodeURIComponent(urlState.profileUrl)];
    default:
      return [];
  }
}

// "null | void" in the query objects are flags which map to true for null, and false
// for void. False flags do not show up the URL.
type BaseQuery = {
  range?: string, //
  thread?: string, // "3"
  threadOrder?: string, // "3-2-0-1"
  hiddenThreads?: string | void, // "0-1"
  react_perf?: null, // Flag to activate react's UserTimings profiler.
  transforms?: string,
};

type CallTreeQuery = BaseQuery & {
  search?: string, // "js::RunScript"
  invertCallstack?: null | void,
  implementation?: string,
};

type MarkersQuery = BaseQuery & {
  markerSearch?: string, // "DOMEvent"
};

type StackChartQuery = BaseQuery & {
  search?: string, // "js::RunScript"
  invertCallstack?: null | void,
  implementation?: string,
};

type UrlObject = {
  pathParts: string[],
  query: Query,
};

type Query = BaseQuery | CallTreeQuery | MarkersQuery | StackChartQuery;

/**
 * Take the UrlState and map it into a serializable UrlObject, that represents the
 * target URL.
 */
export function urlStateToUrlObject(urlState: UrlState): UrlObject {
  const { dataSource } = urlState;
  if (dataSource === 'none') {
    return {
      pathParts: [],
      query: {},
    };
  }
  const pathParts = [...dataSourceDirs(urlState), urlState.selectedTab];

  // Start with the query parameters that are shown regardless of the active tab.
  const query: Object = {
    range: stringifyRangeFilters(urlState.rangeFilters) || undefined,
    thread: urlState.selectedThread,
    threadOrder: urlState.threadOrder.join('-'),
    file: urlState.pathInZipFile || undefined,
    v: CURRENT_URL_VERSION,
  };

  // Add the parameter hiddenThreads only when needed
  if (urlState.hiddenThreads.length > 0) {
    query.hiddenThreads = urlState.hiddenThreads.join('-');
  }

  if (process.env.NODE_ENV === 'development') {
    /* eslint-disable camelcase */
    query.react_perf = null;
    /* eslint-enable camelcase */
  }

  // Depending on which tab is active, also show tab-specific query parameters.
  const selectedTab = urlState.selectedTab;
  switch (selectedTab) {
    case 'stack-chart':
    case 'calltree': {
      query.search = urlState.callTreeSearchString || undefined;
      query.invertCallstack = urlState.invertCallstack ? null : undefined;
      query.implementation =
        urlState.implementation === 'combined'
          ? undefined
          : urlState.implementation;
      const selectedThread = urlState.selectedThread;
      if (selectedThread !== null) {
        query.transforms =
          stringifyTransforms(urlState.transforms[selectedThread]) || undefined;
      }
      break;
    }
    case 'marker-table':
      query.markerSearch = urlState.markersSearchString;
      break;
    case 'marker-chart':
    case 'flame-graph':
      break;
    default:
      assertExhaustiveCheck(selectedTab);
  }
  return { query, pathParts };
}

export function urlFromState(urlState: UrlState): string {
  const { pathParts, query } = urlStateToUrlObject(urlState);
  const { dataSource } = urlState;
  if (dataSource === 'none') {
    return '/';
  }
  const pathname =
    pathParts.length === 0 ? '/' : '/' + pathParts.join('/') + '/';

  const qString = queryString.stringify(query);
  return pathname + (qString ? '?' + qString : '');
}

function getDataSourceFromPathParts(pathParts: string[]): DataSource {
  const str = pathParts[0] || 'none';
  // With this switch, flow is able to understand that we return a valid value
  switch (str) {
    case 'none':
    case 'from-addon':
    case 'from-file':
    case 'local':
    case 'public':
    case 'from-url':
      return str;
    default:
      throw new Error(`Unexpected data source ${str}`);
  }
}

/**
 * Define only the properties of the window.location object that the function uses
 * so that it can be mocked in tests.
 */
type Location = {
  pathname: string,
  search: string,
  hash: string,
};

export function stateFromLocation(location: Location): UrlState {
  const { pathname, query } = upgradeLocationToCurrentVersion({
    pathname: location.pathname,
    hash: location.hash,
    query: queryString.parse(location.search.substr(1)),
  });

  const pathParts = pathname.split('/').filter(d => d);
  const dataSource = getDataSourceFromPathParts(pathParts);
  const selectedThread = query.thread !== undefined ? +query.thread : 0;

  // https://perf-html.io/public/{hash}/calltree/
  const hasProfileHash = ['local', 'public'].includes(dataSource);

  // https://perf-html.io/from-url/{url}/calltree/
  const hasProfileUrl = ['from-url'].includes(dataSource);

  // The selected tab is the last path part in the URL.
  const selectedTabPathPart = hasProfileHash || hasProfileUrl ? 2 : 1;

  let implementation = 'combined';
  // Don't trust the implementation values from the user. Make sure it conforms
  // to known values.
  if (query.implementation === 'js' || query.implementation === 'cpp') {
    implementation = query.implementation;
  }

  return {
    dataSource,
    hash: hasProfileHash ? pathParts[1] : '',
    profileUrl: hasProfileUrl ? decodeURIComponent(pathParts[1]) : '',
    selectedTab: toValidTabSlug(pathParts[selectedTabPathPart]) || 'calltree',
    rangeFilters: query.range ? parseRangeFilters(query.range) : [],
    selectedThread: selectedThread,
    callTreeSearchString: query.search || '',
    markersSearchString: query.markerSearch || '',
    implementation,
    invertCallstack: query.invertCallstack !== undefined,
    pathInZipFile: query.file || null,
    hiddenThreads: query.hiddenThreads
      ? query.hiddenThreads.split('-').map(index => Number(index))
      : [],
    threadOrder: query.threadOrder
      ? query.threadOrder.split('-').map(index => Number(index))
      : [],
    transforms: {
      [selectedThread]: query.transforms
        ? parseTransforms(query.transforms)
        : [],
    },
  };
}

type ProcessedLocation = { pathname: string, hash: string, query: Object };

export function upgradeLocationToCurrentVersion(
  processedLocation: ProcessedLocation
): ProcessedLocation {
  const urlVersion = +processedLocation.query.v || 0;
  if (urlVersion === CURRENT_URL_VERSION) {
    return processedLocation;
  }

  if (urlVersion > CURRENT_URL_VERSION) {
    throw new Error(
      `Unable to parse a url of version ${urlVersion} - are you running an outdated version of perf.html? ` +
        `The most recent version understood by this version of perf.html is version ${CURRENT_URL_VERSION}.\n` +
        'You can try refreshing this page in case perf.html has updated in the meantime.'
    );
  }
  // Convert to CURRENT_URL_VERSION, one step at a time.
  for (
    let destVersion = urlVersion;
    destVersion <= CURRENT_URL_VERSION;
    destVersion++
  ) {
    if (destVersion in _upgraders) {
      _upgraders[destVersion](processedLocation);
    }
  }

  processedLocation.query.v = CURRENT_URL_VERSION;
  return processedLocation;
}

// _upgraders[i] converts from version i - 1 to version i.
// Every "upgrader" takes the processedLocation as its single argument and mutates it.
/* eslint-disable no-useless-computed-key */
const _upgraders = {
  [0]: (processedLocation: ProcessedLocation) => {
    // Version 1 is the first versioned url.

    // If the pathname is '/', this could be a very old URL that has its information
    // stored in the hash.
    if (processedLocation.pathname === '/') {
      const legacyQuery = Object.assign(
        {},
        processedLocation.query,
        queryString.parse(processedLocation.hash)
      );
      if ('report' in legacyQuery) {
        // Put the report into the pathname.
        processedLocation.pathname = `/public/${legacyQuery.report}/calltree/`;
        processedLocation.hash = '';
        processedLocation.query = {};
      }
    }

    // Instead of implementation filters, we used to have jsOnly flags.
    if (processedLocation.query.jsOnly !== undefined) {
      // Support the old URL structure that had a jsOnly flag.
      delete processedLocation.query.jsOnly;
      processedLocation.query.implementation = 'js';
    }
  },
  [1]: (processedLocation: ProcessedLocation) => {
    // The transform stack was added. Convert the callTreeFilters into the new
    // transforms format.
    if (processedLocation.query.callTreeFilters) {
      // Before: "callTreeFilters=prefix-0KV4KV5KV61KV7KV8K~postfixjs-xFFpUMl"
      // After: "transforms=f-combined-0KV4KV5KV61KV7KV8K~f-js-xFFpUMl-i"
      processedLocation.query.transforms = processedLocation.query.callTreeFilters
        .split('~')
        .map(s => {
          const [type, val] = s.split('-');
          switch (type) {
            case 'prefix':
              return `f-combined-${val}`;
            case 'prefixjs':
              return `f-js-${val}`;
            case 'postfix':
              return `f-combined-${val}-i`;
            case 'postfixjs':
              return `f-js-${val}-i`;
            default:
              return undefined;
          }
        })
        .filter(f => f)
        .join('~');
      delete processedLocation.query.callTreeFilters;
    }
  },
  [2]: (processedLocation: ProcessedLocation) => {
    // Map the tab "timeline" to "stack-chart".
    // Map the tab "markers" to "marker-table".
    processedLocation.pathname = processedLocation.pathname
      // Given:    /public/e71ce9584da34298627fb66ac7f2f245ba5edbf5/timeline/
      // Matches:  $1^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      .replace(/^(\/[^/]+\/[^/]+)\/timeline\/?/, '$1/stack-chart/')
      // Given:    /public/e71ce9584da34298627fb66ac7f2f245ba5edbf5/markers/
      // Matches:  $1^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      .replace(/^(\/[^/]+\/[^/]+)\/markers\/?/, '$1/marker-table/');
  },
  [3]: (processedLocation: ProcessedLocation) => {
    const { query } = processedLocation;
    // Removed "Hide platform details" checkbox from the stack chart.
    if ('hidePlatformDetails' in query) {
      delete query.hidePlatformDetails;
      query.implementation = 'js';
    }
  },
};

if (Object.keys(_upgraders).length - 1 !== CURRENT_URL_VERSION) {
  throw new Error(oneLine`
    CURRENT_URL_VERSION does not match the number of URL upgraders. If you added a
    new upgrader, make sure and bump the CURRENT_URL_VERSION variable.
  `);
}
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require("path");

var FICSClient = require("fics");

var SocketHandler = function(connection) {
  this.connection = connection;

  var self = this;
  this.connection.on("data", function(rawMessage) {
    var message = JSON.parse(rawMessage);

    self[message.operation](message.params);
  });

  this.connection.on("close", function() {
    if (self.interface) {
      self.interface.end();
    }
  });
};

SocketHandler.prototype.sendMessage = function(operation, data) {
  this.connection.write(JSON.stringify({ operation: operation, data: data }));
};

SocketHandler.prototype.passthrough = function(interfaceFn, responseMessage) {
  var self = this;
  this.interface[interfaceFn]().then(function(data) {
    self.sendMessage(responseMessage, data);
  });
};

SocketHandler.prototype.channelList = function() {
  this.passthrough("channelList", "channelList");
};

SocketHandler.prototype.subscribedChannelList = function() {
  this.passthrough("channels", "subscribedChannelList");
};

SocketHandler.prototype.gameList = function() {
  this.passthrough("games", "gameList");
};

SocketHandler.prototype.userList = function() {
  this.passthrough("who", "userList");
};

SocketHandler.prototype.soughtList = function() {
  this.passthrough("sought", "soughtList");
};

SocketHandler.prototype.login = function(params) {
  this.interface = new FICSClient();

  var self = this

  if (process.env.NODE_ENV === "development") {
    var socket = this.interface.getSocket();

    socket.pipe(fs.createWriteStream(path.join(process.cwd(), "log", "session.log"), { flags: "a" }));

    socket.on("data", function(data) {
      self.sendMessage("raw", data.toString());
    });
  }

  this.interface.chat().progress(function(data) {
    self.sendMessage("chatMessage", data);
  });

  this.interface.login(params).then(function(userData) {
    self.sendMessage("login", userData);
  });
};

SocketHandler.prototype.shout = function(messageData) {
  this.interface.shout(messageData.message, messageData.it);
};

SocketHandler.prototype.tell = function(messageData) {
  this.interface.tell(messageData.recipient, messageData.message);
};

SocketHandler.prototype.joinChannel = function(channelData) {
  this.interface.joinChannel(channelData.number);
};

SocketHandler.prototype.leaveChannel = function(channelData) {
  this.interface.leaveChannel(channelData.number);
};

SocketHandler.prototype.observe = function(gameData) {
  var gameNumber = gameData.number;

  var self = this;
  this.interface.observe(gameNumber).progress(function(gameData) {
    self.sendMessage("observeUpdate", { number: gameNumber, update: gameData });
  });
};

SocketHandler.prototype.moveList = function(gameData) {
  var self = this;
  this.interface.moves(gameData.number).then(function(moves) {
    self.sendMessage("moveList", { number: gameData.number, moves: moves });
  });
};

SocketHandler.prototype.observerList = function(gameData) {
  var self = this;
  this.interface.observers(gameData.number).then(function(observers) {
    self.sendMessage("observerList", { number: gameData.number, observers: observers });
  });
};

SocketHandler.prototype.kibitz = function(gameData) {
  this.interface.kibitz(gameData.number, gameData.message);
};

SocketHandler.prototype.whisper = function(gameData) {
  this.interface.whisper(gameData.number, gameData.message);
};

SocketHandler.prototype.unobserve = function(gameData) {
  this.interface.unobserve(gameData.number);
};

module.exports = SocketHandler;
<commit_msg>% s/interface/client/g<commit_after>var fs = require("fs");
var path = require("path");

var FICSClient = require("fics");

var SocketHandler = function(connection) {
  this.connection = connection;

  var self = this;
  this.connection.on("data", function(rawMessage) {
    var message = JSON.parse(rawMessage);

    self[message.operation](message.params);
  });

  this.connection.on("close", function() {
    if (self.client) {
      self.client.end();
    }
  });
};

SocketHandler.prototype.sendMessage = function(operation, data) {
  this.connection.write(JSON.stringify({ operation: operation, data: data }));
};

SocketHandler.prototype.passthrough = function(clientFn, responseMessage) {
  var self = this;
  this.client[clientFn]().then(function(data) {
    self.sendMessage(responseMessage, data);
  });
};

SocketHandler.prototype.channelList = function() {
  this.passthrough("channelList", "channelList");
};

SocketHandler.prototype.subscribedChannelList = function() {
  this.passthrough("channels", "subscribedChannelList");
};

SocketHandler.prototype.gameList = function() {
  this.passthrough("games", "gameList");
};

SocketHandler.prototype.userList = function() {
  this.passthrough("who", "userList");
};

SocketHandler.prototype.soughtList = function() {
  this.passthrough("sought", "soughtList");
};

SocketHandler.prototype.login = function(params) {
  this.client = new FICSClient();

  var self = this

  if (process.env.NODE_ENV === "development") {
    var socket = this.client.getSocket();

    socket.pipe(fs.createWriteStream(path.join(process.cwd(), "log", "session.log"), { flags: "a" }));

    socket.on("data", function(data) {
      self.sendMessage("raw", data.toString());
    });
  }

  this.client.chat().progress(function(data) {
    self.sendMessage("chatMessage", data);
  });

  this.client.login(params).then(function(userData) {
    self.sendMessage("login", userData);
  });
};

SocketHandler.prototype.shout = function(messageData) {
  this.client.shout(messageData.message, messageData.it);
};

SocketHandler.prototype.tell = function(messageData) {
  this.client.tell(messageData.recipient, messageData.message);
};

SocketHandler.prototype.joinChannel = function(channelData) {
  this.client.joinChannel(channelData.number);
};

SocketHandler.prototype.leaveChannel = function(channelData) {
  this.client.leaveChannel(channelData.number);
};

SocketHandler.prototype.observe = function(gameData) {
  var gameNumber = gameData.number;

  var self = this;
  this.client.observe(gameNumber).progress(function(gameData) {
    self.sendMessage("observeUpdate", { number: gameNumber, update: gameData });
  });
};

SocketHandler.prototype.moveList = function(gameData) {
  var self = this;
  this.client.moves(gameData.number).then(function(moves) {
    self.sendMessage("moveList", { number: gameData.number, moves: moves });
  });
};

SocketHandler.prototype.observerList = function(gameData) {
  var self = this;
  this.client.observers(gameData.number).then(function(observers) {
    self.sendMessage("observerList", { number: gameData.number, observers: observers });
  });
};

SocketHandler.prototype.kibitz = function(gameData) {
  this.client.kibitz(gameData.number, gameData.message);
};

SocketHandler.prototype.whisper = function(gameData) {
  this.client.whisper(gameData.number, gameData.message);
};

SocketHandler.prototype.unobserve = function(gameData) {
  this.client.unobserve(gameData.number);
};

module.exports = SocketHandler;
<|endoftext|>


<commit_before>var Cards = new Backbone.Marionette.Application();

Cards.addRegions({
	navRegion: "#nav",
	mainRegion: "#main",
	footerRegion: "#footer"
});

Cards.Router = Backbone.Marionette.AppRouter.extend({
	appRoutes : {
		"pool": "showPool",
		"pool/category/:name": "showPoolCategory",
		"set/list": "listSet",
		"set/details/:setName/:setId": "showSet",
		"set/details/:setName/:setId/new": "newCard",
		"set/learn/:setName/:setId": "learnSet",
		"profile/:id": "showProfile",
		"play/meteor/:id": "playMeteor"
	}
});

var API = {
	listSet: function(){
		Cards.Set.Controller.showListLayout();
	},
	newCard: function(name, id){
		Cards.Set.Controller.showDetailsNewCardLayout(name, id);
	},
	showSet: function(name, id) {
		Cards.Set.Controller.showDetailsLayout(name, id);
	},
	learnSet: function(name, id) {
		Cards.Set.Controller.showLearnLayout(name, id);
	},
	showPool: function() {
		Cards.Pool.Controller.showPoolLayout();
	},
	showPoolCategory: function(name) {
		Cards.Pool.Controller.showPoolCategoryLayout(name);
	},
	showProfile: function(id) {
		Cards.Profile.Controller.showLayout(id);
	},
	playMeteor: function(id) {
		Cards.Game.Controller.showMeteorLayout(id);
	}
};

Cards.navigate = function(route, options) {
	if(typeof(options)==='undefined') options = {};

	Backbone.history.navigate(route, options);
};

Cards.getCurrentRoute = function(){
	return Backbone.history.fragment;
};

Cards.addInitializer(function(){
	new Cards.Router({ controller: API });
});

Cards.on("initialize:after", function() {
	$.ajaxSetup({
	    statusCode: {
	        401: function(){
	            window.location.replace('/login');
	        }
	    }
	});

	$.cookie.json = true;
	var usr = $.cookie('usr');
	$("#usr-profile").text(usr.username);
	$("#usr-profile").attr("href", "/#profile/"+usr.id);

	if(Backbone.history) {
		Backbone.history.start();

		if(this.getCurrentRoute() === "") {
			Cards.trigger("set:list");
		}
	}

	var engine = {
	  compile: function(template) {
	    var compiled = _.template(template);

	    return {
	      render: function(context) { return compiled(context); }
	  	}
	} };

	$("#input-search").typeahead([{
		name: 'category',
		remote:  '/typeahead/set/category?q=%QUERY',
		prefetch: '/typeahead/set/category',
		template: [
		  //'
<%= name %>
',
		  '
<%= value %> Kategorie
',
		  '
<%= count %> <% if(count > 1) { %> Kartensätze <% } else { %>Kartensatz<% } %>
'
		].join(''),
		engine: engine
	},
	{
		name: 'sets',
		remote: '/typeahead/set/visibility?q=%QUERY',
		prefetch: '/typeahead/set/visibility',
		template: [
		  //'
<%= name %>
',
		  '
<%= value %> Kartensatz
',
		  '
<%= description %>
'
		].join(''),
		engine: engine
	}]);

	$("#input-search").on("typeahead:selected", function(ev, datum, name) {
		console.log(datum);
		console.log(name);

		if(name == "category") Cards.trigger("pool:details", datum.value);
		if(name == "sets") Cards.trigger("set:details", datum.value, datum.id);

		$("#input-search").blur().val("");
	})

	console.log("THMcards has started!");
});

/* ROUTING EVENTS */
Cards.on("pool", function(){
	Cards.navigate("pool");
	API.showPool();
})

Cards.on("pool:details", function(name){
	Cards.navigate("pool/category/"+name);
	API.showPoolCategory(name);
})

Cards.on("set:list", function(){
	Cards.navigate("set/list");
	API.listSet();
});

Cards.on("set:details", function(name, id){
	Cards.navigate("set/details/"+name+"/"+id);
	API.showSet(name, id);
})

Cards.on("set:details:new", function(name, id){
	Cards.navigate("set/details/"+name+"/"+id+"/new");
	API.newCard(name, id);
})

Cards.on("set:learn", function(name, id){
	Cards.navigate("set/learn/"+name+"/"+id);
	API.learnSet(name, id);
})

Cards.on("profile", function(id){
	Cards.navigate("profile/"+id);
	API.showProfile(id);
})

Cards.on("play:meteor", function(id){
	Cards.navigate("play/meteor/"+id);
	API.playMeteor(id);
})

function FilteredCollection(collection, options){
    var filtered = new collection.constructor(collection.models, options);

    filtered.filter = function(criteria){
        var items;
        if (criteria){
            items = _.filter(collection.models, function(model) {
            	var persCard = model.get("persCard");
            	var pcard;
            	if(_.isArray(persCard)) {
            		pcard = _.first(model.get("persCard"));
            	} else {
            		pcard = model.get("persCard");
            	}

				if (pcard) {
					console.log(pcard.value.box, criteria);
           			return pcard.value.box == criteria;
           		} else {
           			console.log("no card");
           		}
           		if (_.isUndefined(pcard) && criteria == 1){
           			return true;
           		}
           		else return false;

			});
        } else {
            items = collection.models;
        }
        filtered.reset(items);
    };
    collection.on("change", function(model){
    	console.log("change", collection.models);
        filtered.reset(collection.models);
    });
    collection.on("reset", function(){
    	console.log("reset");
        filtered.reset(collection.models);
    });

    return filtered;
}

<commit_msg>searchfield<commit_after>var Cards = new Backbone.Marionette.Application();

Cards.addRegions({
	navRegion: "#nav",
	mainRegion: "#main",
	footerRegion: "#footer"
});

Cards.Router = Backbone.Marionette.AppRouter.extend({
	appRoutes : {
		"pool": "showPool",
		"pool/category/:name": "showPoolCategory",
		"set/list": "listSet",
		"set/details/:setName/:setId": "showSet",
		"set/details/:setName/:setId/new": "newCard",
		"set/learn/:setName/:setId": "learnSet",
		"profile/:id": "showProfile",
		"play/meteor/:id": "playMeteor"
	}
});

var API = {
	listSet: function(){
		Cards.Set.Controller.showListLayout();
	},
	newCard: function(name, id){
		Cards.Set.Controller.showDetailsNewCardLayout(name, id);
	},
	showSet: function(name, id) {
		Cards.Set.Controller.showDetailsLayout(name, id);
	},
	learnSet: function(name, id) {
		Cards.Set.Controller.showLearnLayout(name, id);
	},
	showPool: function() {
		Cards.Pool.Controller.showPoolLayout();
	},
	showPoolCategory: function(name) {
		Cards.Pool.Controller.showPoolCategoryLayout(name);
	},
	showProfile: function(id) {
		Cards.Profile.Controller.showLayout(id);
	},
	playMeteor: function(id) {
		Cards.Game.Controller.showMeteorLayout(id);
	}
};

Cards.navigate = function(route, options) {
	if(typeof(options)==='undefined') options = {};

	Backbone.history.navigate(route, options);
};

Cards.getCurrentRoute = function(){
	return Backbone.history.fragment;
};

Cards.addInitializer(function(){
	new Cards.Router({ controller: API });
});

Cards.on("initialize:after", function() {
	$.ajaxSetup({
	    statusCode: {
	        401: function(){
	            window.location.replace('/login');
	        }
	    }
	});

	$.cookie.json = true;
	var usr = $.cookie('usr');
	$("#usr-profile").text(usr.username);
	$("#usr-profile").attr("href", "/#profile/"+usr.id);

	if(Backbone.history) {
		Backbone.history.start();

		if(this.getCurrentRoute() === "") {
			Cards.trigger("set:list");
		}
	}

	var engine = {
	  compile: function(template) {
	    var compiled = _.template(template);

	    return {
	      render: function(context) { return compiled(context); }
	  	}
	} };

	$("#input-search").typeahead([{
		name: 'category',
		remote:  '/typeahead/set/category?q=%QUERY',
		prefetch: '/typeahead/set/category',
		template: [
		  //'
<%= name %>
',
		  '
<%= value %> Kategorie
',
		  '
<%= count %> <% if(count > 1) { %> Kartensätze <% } else { %>Kartensatz<% } %>
'
		].join(''),
		engine: engine
	},
	{
		name: 'sets',
		remote: '/typeahead/set/visibility?q=%QUERY',
		prefetch: '/typeahead/set/visibility',
		template: [
		  //'
<%= name %>
',
		  '
<%= value %> Kartensatz
',
		  '
<%= description %>
'
		].join(''),
		engine: engine
	}]);

	$("#input-search").on("typeahead:selected", function(ev, datum, name) {
		console.log(datum);
		console.log(name);

		if(name == "category") Cards.trigger("pool:details", datum.value);
		if(name == "sets") Cards.trigger("set:details", datum.value, datum.id);

		$("#input-search").blur();
	})
	$("#input-search").on("blur", function(){
		$(this).val("");
	})

	console.log("THMcards has started!");
});

/* ROUTING EVENTS */
Cards.on("pool", function(){
	Cards.navigate("pool");
	API.showPool();
})

Cards.on("pool:details", function(name){
	Cards.navigate("pool/category/"+name);
	API.showPoolCategory(name);
})

Cards.on("set:list", function(){
	Cards.navigate("set/list");
	API.listSet();
});

Cards.on("set:details", function(name, id){
	Cards.navigate("set/details/"+name+"/"+id);
	API.showSet(name, id);
})

Cards.on("set:details:new", function(name, id){
	Cards.navigate("set/details/"+name+"/"+id+"/new");
	API.newCard(name, id);
})

Cards.on("set:learn", function(name, id){
	Cards.navigate("set/learn/"+name+"/"+id);
	API.learnSet(name, id);
})

Cards.on("profile", function(id){
	Cards.navigate("profile/"+id);
	API.showProfile(id);
})

Cards.on("play:meteor", function(id){
	Cards.navigate("play/meteor/"+id);
	API.playMeteor(id);
})

function FilteredCollection(collection, options){
    var filtered = new collection.constructor(collection.models, options);

    filtered.filter = function(criteria){
        var items;
        if (criteria){
            items = _.filter(collection.models, function(model) {
            	var persCard = model.get("persCard");
            	var pcard;
            	if(_.isArray(persCard)) {
            		pcard = _.first(model.get("persCard"));
            	} else {
            		pcard = model.get("persCard");
            	}

				if (pcard) {
					console.log(pcard.value.box, criteria);
           			return pcard.value.box == criteria;
           		} else {
           			console.log("no card");
           		}
           		if (_.isUndefined(pcard) && criteria == 1){
           			return true;
           		}
           		else return false;

			});
        } else {
            items = collection.models;
        }
        filtered.reset(items);
    };
    collection.on("change", function(model){
    	console.log("change", collection.models);
        filtered.reset(collection.models);
    });
    collection.on("reset", function(){
    	console.log("reset");
        filtered.reset(collection.models);
    });

    return filtered;
}

<|endoftext|>


<commit_before>"use babel";
/* globals jasmine, spyOn, beforeEach */

import _ from "underscore-plus";

window.__realSetTimeout = window.setTimeout;
window.__realClearTimeout = window.clearTimeout;
window.__real__Now = _._.now;
window.__realSetInterval = window.setInterval;
window.__realClearInterval = window.clearInterval;
jasmine.useMockClock = function () {
	spyOn(window, "setInterval").and.callFake(window.fakeSetInterval);
	spyOn(window, "clearInterval").and.callFake(window.fakeClearInterval);
	spyOn(_._, "now").and.callFake(() => window.now);
	spyOn(window, "setTimeout").and.callFake(window.fakeSetTimeout);
	spyOn(window, "clearTimeout").and.callFake(window.fakeClearTimeout);
};
jasmine.useRealClock = function () {
	window.setTimeout = window.__realSetTimeout;
	window.clearTimeout = window.__realClearTimeout;
	_._.now = window.__real__Now;
	window.setInterval = window.__realSetInterval;
	window.clearInterval = window.__realClearInterval;
};

window.resetTimeouts = function () {
	window.now = 0;
	window.timeoutCount = 0;
	window.intervalCount = 0;
	window.timeouts = [];
	window.intervalTimeouts = {};
};

window.fakeSetTimeout = function (callback, ms) {
	if (!ms) { ms = 0; }
	const id = ++window.timeoutCount;
	window.timeouts.push([id, window.now + ms, callback]);
	return id;
};

window.fakeClearTimeout = function (idToClear) {
	window.timeouts = window.timeouts.filter(([id]) => id !== idToClear);
};

window.fakeSetInterval = function (callback, ms) {
	const id = ++window.intervalCount;
	var action = function () {
		callback();
		return window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms);
	};
	window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms);
	return id;
};

window.fakeClearInterval = function (idToClear) {
	window.fakeClearTimeout(this.intervalTimeouts[idToClear]);
};

window.advanceClock = function (delta) {
	if (!delta) { delta = 1; }
	window.now += delta;

	window.timeouts = window.timeouts.filter(([, strikeTime, callback]) => {
		if (strikeTime <= window.now) {
			callback();
			return false;
		}
		return true;

	});
};

beforeEach(function () {
	window.resetTimeouts();
	window.useMockClock();
	window.advanceClock(1000);
});
<commit_msg>use scoped variables for mock clock<commit_after>"use babel";
/* globals jasmine, spyOn, beforeEach */

import _ from "underscore-plus";

const __realSetTimeout = window.setTimeout;
const __realClearTimeout = window.clearTimeout;
const __real__Now = _._.now;
const __realSetInterval = window.setInterval;
const __realClearInterval = window.clearInterval;

jasmine.useMockClock = function () {
	spyOn(window, "setInterval").and.callFake(window.fakeSetInterval);
	spyOn(window, "clearInterval").and.callFake(window.fakeClearInterval);
	spyOn(_._, "now").and.callFake(() => window.now);
	spyOn(window, "setTimeout").and.callFake(window.fakeSetTimeout);
	spyOn(window, "clearTimeout").and.callFake(window.fakeClearTimeout);
};

jasmine.useRealClock = function () {
	window.setTimeout = __realSetTimeout;
	window.clearTimeout = __realClearTimeout;
	_._.now = __real__Now;
	window.setInterval = __realSetInterval;
	window.clearInterval = __realClearInterval;
};

window.resetTimeouts = function () {
	window.now = 0;
	window.timeoutCount = 0;
	window.intervalCount = 0;
	window.timeouts = [];
	window.intervalTimeouts = {};
};

window.fakeSetTimeout = function (callback, ms) {
	if (!ms) { ms = 0; }
	const id = ++window.timeoutCount;
	window.timeouts.push([id, window.now + ms, callback]);
	return id;
};

window.fakeClearTimeout = function (idToClear) {
	window.timeouts = window.timeouts.filter(([id]) => id !== idToClear);
};

window.fakeSetInterval = function (callback, ms) {
	const id = ++window.intervalCount;
	var action = function () {
		callback();
		return window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms);
	};
	window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms);
	return id;
};

window.fakeClearInterval = function (idToClear) {
	window.fakeClearTimeout(this.intervalTimeouts[idToClear]);
};

window.advanceClock = function (delta) {
	if (!delta) { delta = 1; }
	window.now += delta;

	window.timeouts = window.timeouts.filter(([, strikeTime, callback]) => {
		if (strikeTime <= window.now) {
			callback();
			return false;
		}
		return true;

	});
};

beforeEach(function () {
	window.resetTimeouts();
	window.useMockClock();
	window.advanceClock(1000);
});
<|endoftext|>


<commit_before>var test = require('tap').test;
var VirtualMachine = require('../../src/index');

test('spec', function (t) {
    var vm = new VirtualMachine();

    t.type(VirtualMachine, 'function');
    t.type(vm, 'object');
    t.type(vm.blockListener, 'function');
    t.end();
});

test('create', function (t) {
    t.end();
});

test('move', function (t) {
    t.end();
});

test('change', function (t) {
    t.end();
});

test('delete', function (t) {
    t.end();
});
<commit_msg>Test: take out old blockListener check<commit_after>var test = require('tap').test;
var VirtualMachine = require('../../src/index');

test('spec', function (t) {
    var vm = new VirtualMachine();

    t.type(VirtualMachine, 'function');
    t.type(vm, 'object');
    t.end();
});

test('create', function (t) {
    t.end();
});

test('move', function (t) {
    t.end();
});

test('change', function (t) {
    t.end();
});

test('delete', function (t) {
    t.end();
});
<|endoftext|>