<commit_before>angular.module('n52.core.listSelection')
        .controller('SwcListSelectionCtrl', ['$scope', 'interfaceService', 'statusService', 'timeseriesService', '$rootScope', 'listSelectionSrvc', 'settingsService', 'servicesHelper',
            function ($scope, interfaceService, statusService, timeseriesService, $rootScope, listSelectionSrvc, settingsService, servicesHelper) {
                angular.forEach($scope.parameters, function (param, openedIdx) {
                    $scope.$watch('parameters[' + openedIdx + '].isOpen', function (newVal) {
                        if (newVal) {
                            $scope.selectedParameterIndex = openedIdx;
                            $scope.disableFollowingParameters();
                        }
                    });
                });

                _clearSelection = function () {
                    angular.forEach($scope.parameters, function (parameter) {
                        delete parameter.items;
                        delete parameter.selectedIdx;
                    });
                };

                $rootScope.$on('newProviderSelected', function () {
                    _clearSelection();
                    $scope.openNext(0);
                });

                $scope.createParams = function (url, serviceID) {
                    var params = {
                        service: serviceID
                    };
                    var temp;
                    for (var i = 0; i < $scope.parameters.length; i++) {
                        if (angular.isNumber($scope.parameters[i].selectedIdx)) {
                            var selectedItem = $scope.parameters[i].items[$scope.parameters[i].selectedIdx];
                            if (selectedItem) {
                                for (var j = 0; j < selectedItem.provider.length; j++) {
                                    if (selectedItem.provider[j].url === url && selectedItem.provider[j].serviceID === serviceID) {
                                        params[$scope.parameters[i].type] = selectedItem.provider[j].elemID;
                                        break;
                                    }
                                }
                            }
                        } else {
                            temp = i;
                            break;
                        }
                    }
                    if (Object.keys(params).length === temp + 1 || Object.keys(params).length === 5) {
                        return params;
                    } else {
                        return null;
                    }
                };

                $scope.getItems = function (currParam) {
                    currParam.items = [];
                    if (currParam.type === 'category') {
                        $scope.requestItems(currParam, $scope.getCategories);
                    } else if (currParam.type === 'feature') {
                        $scope.requestItems(currParam, $scope.getFeatures);
                    } else if (currParam.type === 'phenomenon') {
                        $scope.requestItems(currParam, $scope.getPhenomena);
                    } else if (currParam.type === 'procedure') {
                        $scope.requestItems(currParam, $scope.getProcedures);
                    }
                };

                $scope.requestItems = function (currParam, itemsTypeFunc) {
                    var paramConstellation;
                    if (settingsService.aggregateServices && angular.isUndefined(statusService.status.apiProvider.url)) {
                        servicesHelper.doForAllServices(function (provider, url) {
                            paramConstellation = $scope.createParams(url, provider.id);
                            if (paramConstellation)
                                itemsTypeFunc(url, provider.id, currParam, paramConstellation);
                        });
                    } else {
                        var provider = statusService.status.apiProvider;
                        paramConstellation = $scope.createParams(provider.url, provider.serviceID);
                        if (paramConstellation)
                            itemsTypeFunc(provider.url, provider.serviceID, currParam, paramConstellation);
                    }
                };

                $scope.getCategories = function (url, serviceID, currParam, params) {
                    interfaceService.getCategories(null, url, params).then(function (data) {
                        addEntries(data, serviceID, url, currParam);
                    });
                };

                $scope.getFeatures = function (url, serviceID, currParam, params) {
                    interfaceService.getFeatures(null, url, params).then(function (data) {
                        addEntries(data, serviceID, url, currParam);
                    });
                };

                $scope.getPhenomena = function (url, serviceID, currParam, params) {
                    interfaceService.getPhenomena(null, url, params).then(function (data) {
                        addEntries(data, serviceID, url, currParam);
                    });
                };

                $scope.getProcedures = function (url, serviceID, currParam, params) {
                    interfaceService.getProcedures(null, url, params).then(function (data) {
                        addEntries(data, serviceID, url, currParam);
                    });
                };

                addEntries = function (data, serviceID, url, currParam) {
                    angular.forEach(data, function (entry) {
                        var categorie = {
                            serviceID: serviceID,
                            url: url,
                            elemID: entry.id
                        };
                        var idx;
                        for (var i = 0; i < currParam.items.length; i++) {
                            if (currParam.items[i].label.toUpperCase() === entry.label.toUpperCase()) {
                                idx = i;
                                break;
                            }
                        }
                        if (angular.isNumber(idx)) {
                            currParam.items[idx].provider.push(categorie);
                        } else {
                            var newEntry = {
                                label: entry.label,
                                provider: [categorie]
                            };
                            currParam.items.push(newEntry);
                        }
                        currParam.items.push();
                    });
                };

                $scope.openNext = function (currentIdx) {
                    $scope.parameters[currentIdx].isDisabled = false;
                    $scope.selectedParameterIndex = currentIdx;
                    if (currentIdx - 1 >= 0)
                        $scope.parameters[currentIdx - 1].isOpen = false;
                    $scope.parameters[currentIdx].isOpen = true;
                    $scope.getItems($scope.parameters[currentIdx]);
                };

                $scope.disableFollowingParameters = function () {
                    angular.forEach($scope.parameters, function (param, idx) {
                        if (idx > $scope.selectedParameterIndex) {
                            param.isDisabled = true;
                            param.isOpen = false;
                            delete param.selectedIdx;
                            delete param.items;
                        }
                        if (idx >= $scope.selectedParameterIndex) {
                            delete param.headerAddition;
                        }
                    });
                };

                $scope.openItem = function (item, paramIndex) {
                    if (angular.isNumber(paramIndex))
                        $scope.selectedParameterIndex = paramIndex;
                    $scope.disableFollowingParameters();
                    $scope.addItem(item, $scope.selectedParameterIndex);
                    $scope.deselectItems($scope.parameters[$scope.selectedParameterIndex].items);
                    item.selected = true;
                    if ($scope.selectedParameterIndex < $scope.parameters.length - 1) {
                        $scope.openNext($scope.selectedParameterIndex + 1);
                    } else {
                        if (item.provider.length === 1) {
                            $scope.addToDiagram($scope.createParams(item.provider[0].url, item.provider[0].serviceID), item.provider[0].url);
                        }
                    }
                };

                $scope.addItem = function (item, idx) {
                    var parameters = $scope.parameters[idx];
                    for (var i = 0; i < parameters.items.length; i++) {
                        if (parameters.items[i].label === item.label) {
                            parameters.selectedIdx = i;
                            break;
                        }
                    }
                    parameters.headerAddition = item.label;
                };

                $scope.deselectItems = function (items) {
                    angular.forEach(items, function (item) {
                        item.selected = false;
                    });
                };

                $scope.addToDiagram = function (params, url) {
                    timeseriesService.addTimeseriesById(null, url, params);
                };

                if ($scope.listselectionid) {
                    if (listSelectionSrvc.hasEntry($scope.listselectionid)) {
                        $scope.parameters = listSelectionSrvc.getEntry($scope.listselectionid);
                    } else {
                        listSelectionSrvc.setEntry($scope.listselectionid, $scope.parameters);
                        $scope.openNext(0);
                    }
                } else {
                    $scope.openNext(0);
                }
            }])
        .factory('listSelectionSrvc', ['$rootScope', function ($rootScope) {
                var entries = {};
                getEntry = function (id) {
                    return entries[id];
                };
                setEntry = function (id, entry) {
                    entries[id] = entry;
                };
                hasEntry = function (id) {
                    return angular.isDefined(entries[id]);
                };
                $rootScope.$on('newProviderSelected', function () {
                    entries = {};
                });
                return {
                    getEntry: getEntry,
                    setEntry: setEntry,
                    hasEntry: hasEntry
                };
            }]);<commit_msg>support new API in the list selection<commit_after>angular.module('n52.core.listSelection')
    .controller('SwcListSelectionCtrl', ['$scope', 'interfaceService', 'statusService', 'timeseriesService', '$rootScope', 'listSelectionSrvc', 'settingsService', 'servicesHelper',
        function($scope, interfaceService, statusService, timeseriesService, $rootScope, listSelectionSrvc, settingsService, servicesHelper) {
            angular.forEach($scope.parameters, function(param, openedIdx) {
                $scope.$watch('parameters[' + openedIdx + '].isOpen', function(newVal) {
                    if (newVal) {
                        $scope.selectedParameterIndex = openedIdx;
                        $scope.disableFollowingParameters();
                    }
                });
            });

            _clearSelection = function() {
                angular.forEach($scope.parameters, function(parameter) {
                    delete parameter.items;
                    delete parameter.selectedIdx;
                });
            };

            $rootScope.$on('newProviderSelected', function() {
                _clearSelection();
                $scope.openNext(0);
            });

            $scope.createParams = function(url, serviceID) {
                var params = {
                    service: serviceID
                };
                var temp;
                for (var i = 0; i < $scope.parameters.length; i++) {
                    if (angular.isNumber($scope.parameters[i].selectedIdx)) {
                        var selectedItem = $scope.parameters[i].items[$scope.parameters[i].selectedIdx];
                        if (selectedItem) {
                            for (var j = 0; j < selectedItem.provider.length; j++) {
                                if (selectedItem.provider[j].url === url && selectedItem.provider[j].serviceID === serviceID) {
                                    params[$scope.parameters[i].type] = selectedItem.provider[j].elemID;
                                    break;
                                }
                            }
                        }
                    } else {
                        temp = i;
                        break;
                    }
                }
                if (Object.keys(params).length === temp + 1 || Object.keys(params).length === 5) {
                    return params;
                } else {
                    return null;
                }
            };

            $scope.getItems = function(currParam) {
                currParam.items = [];
                if (currParam.type === 'category') {
                    $scope.requestItems(currParam, $scope.getCategories);
                } else if (currParam.type === 'feature') {
                    $scope.requestItems(currParam, $scope.getFeatures);
                } else if (currParam.type === 'phenomenon') {
                    $scope.requestItems(currParam, $scope.getPhenomena);
                } else if (currParam.type === 'procedure') {
                    $scope.requestItems(currParam, $scope.getProcedures);
                }
            };

            $scope.requestItems = function(currParam, itemsTypeFunc) {
                var paramConstellation;
                if (settingsService.aggregateServices && angular.isUndefined(statusService.status.apiProvider.url)) {
                    servicesHelper.doForAllServices(function(provider, url) {
                        paramConstellation = $scope.createParams(url, provider.id);
                        if (paramConstellation)
                            itemsTypeFunc(url, provider.id, currParam, paramConstellation);
                    });
                } else {
                    var provider = statusService.status.apiProvider;
                    paramConstellation = $scope.createParams(provider.url, provider.serviceID);
                    if (paramConstellation)
                        itemsTypeFunc(provider.url, provider.serviceID, currParam, paramConstellation);
                }
            };

            $scope.getCategories = function(url, serviceID, currParam, params) {
                interfaceService.getCategories(null, url, params).then(function(data) {
                    addEntries(data, serviceID, url, currParam);
                });
            };

            $scope.getFeatures = function(url, serviceID, currParam, params) {
                interfaceService.getFeatures(null, url, params).then(function(data) {
                    addEntries(data, serviceID, url, currParam);
                });
            };

            $scope.getPhenomena = function(url, serviceID, currParam, params) {
                interfaceService.getPhenomena(null, url, params).then(function(data) {
                    addEntries(data, serviceID, url, currParam);
                });
            };

            $scope.getProcedures = function(url, serviceID, currParam, params) {
                interfaceService.getProcedures(null, url, params).then(function(data) {
                    addEntries(data, serviceID, url, currParam);
                });
            };

            addEntries = function(data, serviceID, url, currParam) {
                angular.forEach(data, function(entry) {
                    var categorie = {
                        serviceID: serviceID,
                        url: url,
                        elemID: entry.id
                    };
                    var idx;
                    for (var i = 0; i < currParam.items.length; i++) {
                        if (currParam.items[i].label.toUpperCase() === entry.label.toUpperCase()) {
                            idx = i;
                            break;
                        }
                    }
                    if (angular.isNumber(idx)) {
                        currParam.items[idx].provider.push(categorie);
                    } else {
                        var newEntry = {
                            label: entry.label,
                            provider: [categorie]
                        };
                        currParam.items.push(newEntry);
                    }
                    currParam.items.push();
                });
            };

            $scope.openNext = function(currentIdx) {
                $scope.parameters[currentIdx].isDisabled = false;
                $scope.selectedParameterIndex = currentIdx;
                if (currentIdx - 1 >= 0)
                    $scope.parameters[currentIdx - 1].isOpen = false;
                $scope.parameters[currentIdx].isOpen = true;
                $scope.getItems($scope.parameters[currentIdx]);
            };

            $scope.disableFollowingParameters = function() {
                angular.forEach($scope.parameters, function(param, idx) {
                    if (idx > $scope.selectedParameterIndex) {
                        param.isDisabled = true;
                        param.isOpen = false;
                        delete param.selectedIdx;
                        delete param.items;
                    }
                    if (idx >= $scope.selectedParameterIndex) {
                        delete param.headerAddition;
                    }
                });
            };

            $scope.openItem = function(item, paramIndex) {
                if (angular.isNumber(paramIndex))
                    $scope.selectedParameterIndex = paramIndex;
                $scope.disableFollowingParameters();
                $scope.addItem(item, $scope.selectedParameterIndex);
                $scope.deselectItems($scope.parameters[$scope.selectedParameterIndex].items);
                item.selected = true;
                if ($scope.selectedParameterIndex < $scope.parameters.length - 1) {
                    $scope.openNext($scope.selectedParameterIndex + 1);
                } else {
                    if (item.provider.length === 1) {
                        $scope.addToDiagram($scope.createParams(item.provider[0].url, item.provider[0].serviceID), item.provider[0].url);
                    }
                }
            };

            $scope.addItem = function(item, idx) {
                var parameters = $scope.parameters[idx];
                for (var i = 0; i < parameters.items.length; i++) {
                    if (parameters.items[i].label === item.label) {
                        parameters.selectedIdx = i;
                        break;
                    }
                }
                parameters.headerAddition = item.label;
            };

            $scope.deselectItems = function(items) {
                angular.forEach(items, function(item) {
                    item.selected = false;
                });
            };

            $scope.addToDiagram = function(params, url) {
                timeseriesService.addTimeseriesById(null, url, params);
            };

            if ($scope.listselectionid) {
                if (listSelectionSrvc.hasEntry($scope.listselectionid)) {
                    $scope.parameters = listSelectionSrvc.getEntry($scope.listselectionid);
                } else {
                    listSelectionSrvc.setEntry($scope.listselectionid, $scope.parameters);
                    $scope.openNext(0);
                }
            } else {
                $scope.openNext(0);
            }
        }
    ])
    .factory('listSelectionSrvc', ['$rootScope', function($rootScope) {
        var entries = {};
        getEntry = function(id) {
            return entries[id];
        };
        setEntry = function(id, entry) {
            entries[id] = entry;
        };
        hasEntry = function(id) {
            return angular.isDefined(entries[id]);
        };
        $rootScope.$on('newProviderSelected', function() {
            entries = {};
        });
        return {
            getEntry: getEntry,
            setEntry: setEntry,
            hasEntry: hasEntry
        };
    }]);
<|endoftext|>


<commit_before>"use strict";

var expect = require("chai").use(require("sinon-chai")).expect;
var sinon = require("sinon");

describe("The ajax interceptor", function () {
  var $rootScope, $q, AppEvents, interceptor;

  beforeEach(function () {
    $rootScope = {$broadcast: sinon.spy()};
    $q = {};
    AppEvents = require("../../internal/events");
  });

  beforeEach(function () {
    var AjaxInterceptorService = require("./ajax_interceptor_service");
    interceptor = new AjaxInterceptorService($rootScope, $q, AppEvents);
  });

  it("should emit the request started event when a request is intercepted", function () {
    interceptor.request({});

    expect($rootScope.$broadcast).to.have.been.calledWith(AppEvents.HTTP.REQUEST_STARTED);
  });

  it("should emit the request ended event when a response is intercepted", function () {
    interceptor.response({});

    expect($rootScope.$broadcast).to.have.been.calledWith(AppEvents.HTTP.REQUEST_ENDED);
  });

  it("should emit the request ended event when a request failed", function () {
    interceptor.response({});

    expect($rootScope.$broadcast).to.have.been.calledWith(AppEvents.HTTP.REQUEST_ENDED);
  });
});<commit_msg>Ensure the ajax interceptor is defined<commit_after>"use strict";

var expect = require("chai").use(require("sinon-chai")).expect;
var sinon = require("sinon");

describe("The ajax interceptor", function () {
  var $rootScope, $q, AppEvents, interceptor;

  beforeEach(function () {
    $rootScope = {$broadcast: sinon.spy()};
    $q = {};
    AppEvents = require("../../internal/events");
  });

  beforeEach(function () {
    var AjaxInterceptorService = require("./ajax_interceptor_service");
    interceptor = new AjaxInterceptorService($rootScope, $q, AppEvents);
  });

  it("should be defined", function () {
    expect(interceptor).to.be.defined;
  });

  it("should emit the request started event when a request is intercepted", function () {
    interceptor.request({});

    expect($rootScope.$broadcast).to.have.been.calledWith(AppEvents.HTTP.REQUEST_STARTED);
  });

  it("should emit the request ended event when a response is intercepted", function () {
    interceptor.response({});

    expect($rootScope.$broadcast).to.have.been.calledWith(AppEvents.HTTP.REQUEST_ENDED);
  });

  it("should emit the request ended event when a request failed", function () {
    interceptor.response({});

    expect($rootScope.$broadcast).to.have.been.calledWith(AppEvents.HTTP.REQUEST_ENDED);
  });
});<|endoftext|>


<commit_before>let self = require("sdk/self");
let simplePrefs = require("sdk/simple-prefs");
let clipboard = require("sdk/clipboard");
let tabs = require("sdk/tabs");
let contextMenu = require("sdk/context-menu");
let properties = require("packages/properties");
let gifRequestBlocker = require("packages/gifRequestBlocker");
let resImageViewerModHelper = require("./resImageViewerModHelper");

const CONTEXT_MENU_CONTEXT_SELECTOR = "img[src*=\".gif\"], a[href*=\".gif\"]";

// ------------------------------------------------------------------------------
// Setup listeners
// ------------------------------------------------------------------------------

simplePrefs.on("redirectDirectGifRequests", () => {
  gifRequestBlocker.enable(simplePrefs.prefs.redirectDirectGifRequests);
});

simplePrefs.on("resImageViewerSupport", () => {
  let enable = simplePrefs.prefs.resImageViewerSupport;
  resImageViewerModHelper.enable(enable);
  gifRequestBlocker.enable(enable);
});

// ------------------------------------------------------------------------------
// Setup context menu
// ------------------------------------------------------------------------------

contextMenu.Item({
  label: "Open with gfycat",
  data: "gccfx-openWithGfyCat",
  context: contextMenu.SelectorContext("img[src*=\".gif\"]"),
  contentScriptFile: self.data.url("pagemod/contextMenuClick.js"),
  image: self.data.url("images/icon-16.png"),
  onMessage: function (link) {
    tabs.open(properties.gfycat.fetchEndpoint + link);
  }
});

contextMenu.Item({
  label: "Copy as gfycat URL",
  data: "gccfx-menuItemCopyAsGfycatUrl",
  context: contextMenu.SelectorContext("img[src*=\".gif\"], a[href*=\".gif\"]"),
  contentScriptFile: self.data.url("pagemod/contextMenuClick.js"),
  image: self.data.url("images/icon-16.png"),
  onMessage: function (link) {
    clipboard.set(properties.gfycat.fetchEndpoint + link);
  }
});

// ------------------------------------------------------------------------------
// Start
// ------------------------------------------------------------------------------

gifRequestBlocker.enable(simplePrefs.prefs.redirectDirectGifRequests);
resImageViewerModHelper.enable(simplePrefs.prefs.resImageViewerSupport);<commit_msg>remove unused code<commit_after>let self = require("sdk/self");
let simplePrefs = require("sdk/simple-prefs");
let clipboard = require("sdk/clipboard");
let tabs = require("sdk/tabs");
let contextMenu = require("sdk/context-menu");
let properties = require("packages/properties");
let gifRequestBlocker = require("packages/gifRequestBlocker");
let resImageViewerModHelper = require("./resImageViewerModHelper");

// ------------------------------------------------------------------------------
// Setup listeners
// ------------------------------------------------------------------------------

simplePrefs.on("redirectDirectGifRequests", () => {
  gifRequestBlocker.enable(simplePrefs.prefs.redirectDirectGifRequests);
});

simplePrefs.on("resImageViewerSupport", () => {
  let enable = simplePrefs.prefs.resImageViewerSupport;
  resImageViewerModHelper.enable(enable);
  gifRequestBlocker.enable(enable);
});

// ------------------------------------------------------------------------------
// Setup context menu
// ------------------------------------------------------------------------------

contextMenu.Item({
  label: "Open with gfycat",
  data: "gccfx-openWithGfyCat",
  context: contextMenu.SelectorContext("img[src*=\".gif\"]"),
  contentScriptFile: self.data.url("pagemod/contextMenuClick.js"),
  image: self.data.url("images/icon-16.png"),
  onMessage: function (link) {
    tabs.open(properties.gfycat.fetchEndpoint + link);
  }
});

contextMenu.Item({
  label: "Copy as gfycat URL",
  data: "gccfx-menuItemCopyAsGfycatUrl",
  context: contextMenu.SelectorContext("img[src*=\".gif\"], a[href*=\".gif\"]"),
  contentScriptFile: self.data.url("pagemod/contextMenuClick.js"),
  image: self.data.url("images/icon-16.png"),
  onMessage: function (link) {
    clipboard.set(properties.gfycat.fetchEndpoint + link);
  }
});

// ------------------------------------------------------------------------------
// Start
// ------------------------------------------------------------------------------

gifRequestBlocker.enable(simplePrefs.prefs.redirectDirectGifRequests);
resImageViewerModHelper.enable(simplePrefs.prefs.resImageViewerSupport);<|endoftext|>


<commit_before>const cli = require('commander')
const moment = require('moment')
const chalk = require('chalk')
const apiCall = require('./apiCall')

const periods = []

cli
  .option('-f, --from <date>', 'select from <date>.', validateDate)
  .option('-t, --to <date>', 'select to <date>.', validateDate)
  .parse(process.argv)

function printReports () {
  definePeriods()
  periods.forEach(period => {
    apiCall('completed', '', {
      start_date: period[0].format('YYYY-MM-DDTHH:MM:ssZ'),
      end_date: period[1].format('YYYY-MM-DDTHH:MM:ssZ')
    })
    .then(res => {
      let report = new Report(res.body, period)
      report.create()
      report.print()
    })
  })
}

function definePeriods () {
  // Add one hour to the default end time to take inconsistencies into account.
  const defaultEndTime = moment.utc().add(1, 'h')
  // Make default periods if the user didn't input any.
  if (!cli.args.length && !cli.to && !cli.from) {
    let month = formatMonth((moment().month() + 1).toString())
    periods.push([moment.utc('2014-01-01'), defaultEndTime])
    periods.push([moment.utc(month), defaultEndTime])
  }
  // Make month periods.
  cli.args.forEach(month => {
    let start = validateDate(formatMonth(month))
    let end = moment(start).add(1, 'M')
    periods.push([start, end])
  })
  // Make options periods.
  if (cli.from || cli.to) {
    let start = cli.from ? cli.from : moment.utc('2014-01-01')
    let end = cli.to ? cli.to : defaultEndTime
    periods.push([start, end])
  }
}

function formatMonth (month) {
  return month.length === 1 ? `${moment().year()}-0${month}`
                            : `${moment().year()}-${month}`
}

function validateDate (date) {
  date = moment.utc(date)
  if (!date.isValid()) {
    throw new Error(`Invalid date: ${date}`)
  }
  return date
}

class Report {
  constructor (reviews, period) {
    this.period = period
    this.reviews = reviews
    this.projects = {}
    this.totalEarned = 0
  }

  create () {
    this.reviews.forEach(review => {
      this.countReview(review)
    })
  }

  countReview (review) {
    let id = review.project_id
    let price = parseInt(review.price)

    // If the report does not yet contain an entry for the project type, create
    // the entry and try counting the review again.
    if (!this.projects.hasOwnProperty(id)) {
      this.projects[id] = {
        name: review.project.name,
        id: id,
        passed: 0,
        failed: 0,
        ungradeable: 0,
        earned: 0
      }
      this.countReview(review)
    } else {
      this.projects[id][review.result] += 1
      this.projects[id].earned += price
      this.totalEarned += price
    }
  }

  print () {
    let startDate = moment(this.period[0]).format('YYYY-MM-DD')
    let endDate = moment(this.period[1]).format('YYYY-MM-DD')

    console.log('========================================')
    console.log(chalk.blue(`Earnings Report for ${startDate} to ${endDate}:`))

    for (let p in this.projects) {
      let {name, id, ungradeable, passed, failed, earned} = this.projects[p]
      console.log(`
      ${chalk.white(`Project: ${name} (${id}):`)}
          ${chalk.white(`Total reviewed: ${passed + failed}`)}
          ${chalk.white(`Ungradeable: ${ungradeable}`)}
          ${chalk.white(`Earned: ${earned}`)}
          `)
    }
    console.log(chalk.bgBlack.white(`Total Earned: ${this.totalEarned}`))
    console.log('========================================')
  }
}

printReports()
<commit_msg>Add 'today' and 'yesterday' to the money command<commit_after>const cli = require('commander')
const moment = require('moment')
const chalk = require('chalk')
const apiCall = require('./apiCall')

const periods = []

cli
  .option('-f, --from <date>', 'select from <date>.', validateDate)
  .option('-t, --to <date>', 'select to <date>.', validateDate)
  .parse(process.argv)

function printReports () {
  definePeriods()
  periods.forEach(period => {
    apiCall('completed', '', {
      start_date: period[0].format('YYYY-MM-DDTHH:MM:ssZ'),
      end_date: period[1].format('YYYY-MM-DDTHH:MM:ssZ')
    })
    .then(res => {
      let report = new Report(res.body, period)
      report.create()
      report.print()
    })
  })
}

function definePeriods () {
  // Add one hour to the default end time to take inconsistencies into account.
  const defaultEndTime = moment.utc().add(1, 'h')
  // Make default periods if the user didn't input any.
  if (!cli.args.length && !cli.to && !cli.from) {
    let month = formatMonth((moment().month() + 1).toString())
    periods.push([moment.utc('2014-01-01'), defaultEndTime])
    periods.push([moment.utc(month), defaultEndTime])
  }
  // Make options periods.
  if (cli.from || cli.to) {
    let start = cli.from ? cli.from : moment.utc('2014-01-01')
    let end = cli.to ? cli.to : defaultEndTime
    periods.push([start, end])
  }
  cli.args.forEach(arg => {
    // If it's an integer we assume it's a month
    if (parseInt(arg)) {
      let start = moment().utc().month(arg - 1).startOf('month')
      let end = moment().utc().month(arg - 1).add(1, 'M')
      periods.push([start, end])
    } else if (arg === 'today') {
      let start = moment.utc().startOf('day')
      let end = moment.utc().endOf('day')
      periods.push([start, end])
    } else if (arg === 'yesterday') {
      let start = moment.utc().subtract(1, 'd').startOf('day')
      let end = moment.utc().subtract(1, 'd').endOf('day')
      periods.push([start, end])
    }
  })
}

function formatMonth (month) {
  return month.length === 1 ? `${moment().year()}-0${month}`
                            : `${moment().year()}-${month}`
}

function validateDate (date) {
  date = moment.utc(date)
  if (!date.isValid()) {
    throw new Error(`Invalid date: ${date}`)
  }
  return date
}

class Report {
  constructor (reviews, period) {
    this.period = period
    this.reviews = reviews
    this.projects = {}
    this.totalEarned = 0
  }

  create () {
    this.reviews.forEach(review => {
      this.countReview(review)
    })
  }

  countReview (review) {
    let id = review.project_id
    let price = parseInt(review.price)

    // If the report does not yet contain an entry for the project type, create
    // the entry and try counting the review again.
    if (!this.projects.hasOwnProperty(id)) {
      this.projects[id] = {
        name: review.project.name,
        id: id,
        passed: 0,
        failed: 0,
        ungradeable: 0,
        earned: 0
      }
      this.countReview(review)
    } else {
      this.projects[id][review.result] += 1
      this.projects[id].earned += price
      this.totalEarned += price
    }
  }

  print () {
    let startDate = moment(this.period[0]).format('YYYY-MM-DD')
    let endDate = moment(this.period[1]).format('YYYY-MM-DD')

    console.log('========================================')
    console.log(chalk.blue(`Earnings Report for ${startDate} to ${endDate}:`))

    for (let p in this.projects) {
      let {name, id, ungradeable, passed, failed, earned} = this.projects[p]
      console.log(`
      ${chalk.white(`Project: ${name} (${id}):`)}
          ${chalk.white(`Total reviewed: ${passed + failed}`)}
          ${chalk.white(`Ungradeable: ${ungradeable}`)}
          ${chalk.white(`Earned: ${earned}`)}
          `)
    }
    console.log(chalk.bgBlack.white(`Total Earned: ${this.totalEarned}`))
    console.log('========================================')
  }
}

printReports()
<|endoftext|>


<commit_before>var c;

$("#permalink").hide();
$("#timewrap").hide();

// If browser supports history pushStete, avoid reloading page on query change
if (typeof(history) == "object" && typeof(history.pushState) == "function") {
  $("#queryfrom").on("submit", function(e) {
    var query = $("#query").val();
    history.pushState({query: query}, document.title, "/?query=" + encodeURIComponent(query));
    e.preventDefault();
    q();
  });
  $(window).on("popstate", function(e) {
    var m = window.location.search.match(/(\?|&)query=(.*)(&|$)/);
    var query = m ? decodeURIComponent(m[2]) : "";
    if (query) {
      $("#query").val(query);
      q();
    } else {
      window.location.reload();
    }
  });
}

var QueryString = function () {
                    // This function is anonymous, is executed immediately and
                    // the return value is assigned to QueryString!
                    var query_string = {};
                    var query = window.location.search.substring(1);
                    var vars = query.split("&");
                    for (var i=0;i<vars.length;i++) {
                      var pair = vars[i].split("=");
                      // If first entry with this name
                      if (typeof query_string[pair[0]] === "undefined") {
                        query_string[pair[0]] = pair[1];
                        // If second entry with this name
                      } else if (typeof query_string[pair[0]] === "string") {
                        var arr = [ query_string[pair[0]], pair[1] ];
                        query_string[pair[0]] = arr;
                        // If third or later entry with this name
                      } else {
                        query_string[pair[0]].push(pair[1]);
                      }
                    }
                    return query_string;
                  }();

if (QueryString.metric && QueryString.bucket) {
  var metric = decodeURIComponent(QueryString.metric);
  var bucket = decodeURIComponent(QueryString.bucket);
  if (! bucket.match(/^'.*'$/)) {
    bucket = "'" + bucket + "'";
  }
  $("#query").val("SELECT " + metric + " BUCKET " + bucket + " LAST 60s");
  q();
} else if (QueryString.query) {
  var query = decodeURIComponent(QueryString.query).replace(/\+/g, ' ');
  $("#query").val(query);
  q();
}

function render_metrics(start, metrics, markers) {
  var data,
      legend = [];
  $("#results").text("");
  if (metrics.length > 0) {
    $("#results").append($("

").text("Metrics")).append($("
"))
    data = metrics.map(function(s) {
             var resolution = s.resolution,
                 values = s.values,
                 points = new Array(values.length);

             legend.push(s.name);
             for (var i = 0; i < values.length; i++) {
               points[i] = {
                 "date": new Date(start + (i * resolution)),
                 "value": values[i]
               };
             }
             return points;
           });

    MG.data_graphic({
      data: data,
      height: 400,
      markers: markers,
      full_width: true,
      target: '#results',
      legend: legend,
      max_data_size: 11,
      legend_target: '#legend',
      missing_is_hidden: true,
      aggregate_rollover: true
    });
  }
}

function render_event(event) {
  var div = $("

"),
      hdr = $("

").text(event.name),
      tbl = $("

"),
      th  = $("

Date	Event

"),
      tb  = $("

");
  event.values.map(function (e) {
    var tr = $("

"),
        date = new Date(e.timestamp/1000/1000);
    tr.append($("	").text(date))
    .append($("	").append($("

").text(JSON.stringify(e.event, null, 2))));
    tb.append(tr)
  });
  tbl.append(th)
  tbl.append(tb)
  div.append(hdr) .append(tbl)
  $("#events").append(div)
}
function render_events(start, events) {
  $("#events").text("");
  if (events.length > 0) {
    $("#events").append($("

").text("Events")).append($("
"))
    events.map(render_event)
  }
}

function render_graph(graph) {
  $("#graph").text("")
  if (graph) {
    $("#graph").append($("

").text("Query graph")).append($("
").append(Viz(graph)))
  }
}

function q() {
  var query = $("#query").val();
  var base = "?"
  $("#events").text("").append($("
"))
  if ($("#debug").is(':checked')) {
    base = "?graph&q=";
  } else {
    base = "?q=";
  }
  msgpack.download(base + query, {header: {accept:"application/x-msgpack"}}, function(res) {
    $("#permalink").attr("href", "/?query=" + encodeURIComponent(query));
    $("#permalink").show();
    $("#time").text((res.query_time / 1000) + "ms");
    $("#timewrap").show();

    var start = res.start * 1000,
        markers = [];

    gres = res
    metrics = res.results.filter(function(e) {
                return e.type == "metrics"
              });
    console.log(metrics[0])
    console.log("Fetched " + metrics[0].values.length * metrics.length + " elements in " +
                res.query_time / 1000 + "ms");
    events = res.results.filter(function(e) {
               return e.type == "events"
             });
    render_metrics(start, metrics, markers);
    render_events(start, events);
    render_graph(res.graph)

  });
}
<commit_msg>Add debug<commit_after>var c;

$("#permalink").hide();
$("#timewrap").hide();

// If browser supports history pushStete, avoid reloading page on query change
if (typeof(history) == "object" && typeof(history.pushState) == "function") {
  $("#queryfrom").on("submit", function(e) {
    var query = $("#query").val();
    history.pushState({query: query}, document.title, "/?query=" + encodeURIComponent(query));
    e.preventDefault();
    q();
  });
  $(window).on("popstate", function(e) {
    var m = window.location.search.match(/(\?|&)query=(.*)(&|$)/);
    var query = m ? decodeURIComponent(m[2]) : "";
    if (query) {
      $("#query").val(query);
      q();
    } else {
      window.location.reload();
    }
  });
}

var QueryString = function () {
                    // This function is anonymous, is executed immediately and
                    // the return value is assigned to QueryString!
                    var query_string = {};
                    var query = window.location.search.substring(1);
                    var vars = query.split("&");
                    for (var i=0;i<vars.length;i++) {
                      var pair = vars[i].split("=");
                      // If first entry with this name
                      if (typeof query_string[pair[0]] === "undefined") {
                        query_string[pair[0]] = pair[1];
                        // If second entry with this name
                      } else if (typeof query_string[pair[0]] === "string") {
                        var arr = [ query_string[pair[0]], pair[1] ];
                        query_string[pair[0]] = arr;
                        // If third or later entry with this name
                      } else {
                        query_string[pair[0]].push(pair[1]);
                      }
                    }
                    return query_string;
                  }();

if (QueryString.metric && QueryString.bucket) {
  var metric = decodeURIComponent(QueryString.metric);
  var bucket = decodeURIComponent(QueryString.bucket);
  if (! bucket.match(/^'.*'$/)) {
    bucket = "'" + bucket + "'";
  }
  $("#query").val("SELECT " + metric + " BUCKET " + bucket + " LAST 60s");
  q();
} else if (QueryString.query) {
  var query = decodeURIComponent(QueryString.query).replace(/\+/g, ' ');
  $("#query").val(query);
  q();
}

function render_metrics(start, metrics, markers) {
  var data,
      legend = [];
  $("#results").text("");
  if (metrics.length > 0) {
    $("#results").append($("

").text("Metrics")).append($("
"))
    data = metrics.map(function(s) {
             var resolution = s.resolution,
                 values = s.values,
                 points = new Array(values.length);

             legend.push(s.name);
             for (var i = 0; i < values.length; i++) {
               points[i] = {
                 "date": new Date(start + (i * resolution)),
                 "value": values[i]
               };
             }
             return points;
           });

    MG.data_graphic({
      data: data,
      height: 400,
      markers: markers,
      full_width: true,
      target: '#results',
      legend: legend,
      max_data_size: 11,
      legend_target: '#legend',
      missing_is_hidden: true,
      aggregate_rollover: true
    });
  }
}

function render_event(event) {
  var div = $("

"),
      hdr = $("

").text(event.name),
      tbl = $("

"),
      th  = $("

Date	Event

"),
      tb  = $("

");
  event.values.map(function (e) {
    var tr = $("

"),
        date = new Date(e.timestamp/1000/1000);
    tr.append($("	").text(date))
    .append($("	").append($("

").text(JSON.stringify(e.event, null, 2))));
    tb.append(tr)
  });
  tbl.append(th)
  tbl.append(tb)
  div.append(hdr) .append(tbl)
  $("#events").append(div)
}
function render_events(start, events) {
  $("#events").text("");
  if (events.length > 0) {
    $("#events").append($("

").text("Events")).append($("
"))
    events.map(render_event)
  }
}

function render_graph(graph) {
  $("#graph").text("")
  if (graph) {
    $("#graph")
    .append($("

").text("Query graph"))
    .append($("
")
            .append(Viz(graph, {scale: 0.1})))
  }
}

function q() {
  var query = $("#query").val();
  var base = "?"
  $("#events").text("").append($("
"))
  if ($("#debug").is(':checked')) {
    base = "?graph&q=";
  } else {
    base = "?q=";
  }
  msgpack.download(base + query, {header: {accept:"application/x-msgpack"}}, function(res) {
    $("#permalink").attr("href", "/?query=" + encodeURIComponent(query));
    $("#permalink").show();
    $("#time").text((res.query_time / 1000) + "ms");
    $("#timewrap").show();

    var start = res.start * 1000,
        markers = [];

    gres = res
    metrics = res.results.filter(function(e) {
                return e.type == "metrics"
              });
    console.log(metrics[0])
    console.log("Fetched " + metrics[0].values.length * metrics.length + " elements in " +
                res.query_time / 1000 + "ms");
    events = res.results.filter(function(e) {
               return e.type == "events"
             });
    render_metrics(start, metrics, markers);
    render_events(start, events);
    render_graph(res.graph)

  });
}
<|endoftext|>


<commit_before>'use strict';

angular.module('core')

.factory('$Core', [

    '$http',

    function( $http ) {

        var jsonUrl = null;

        return  {

            getJsonUrl: function(){

                if( jsonUrl === null ){
                    jsonUrl = document.querySelector("link[rel='https://github.com/WP-API/WP-API']").href;
                    return jsonUrl;
                }else{
                    return jsonUrl;
                }
            }

        };
    }
])

;
<commit_msg>Changed the get json url to reflect new use of permalinks<commit_after>'use strict';

angular.module('core')

.factory('$Core', [

    '$http',

    function( $http ) {

        var jsonUrl = null;

        return  {

            getJsonUrl: function(){

                if( jsonUrl === null ){
                    jsonUrl = document.querySelector("link[rel='https://github.com/WP-API/WP-API']").href + '/';
                    return jsonUrl;
                }else{
                    return jsonUrl;
                }
            }

        };
    }
])

;
<|endoftext|>


<commit_before>'use strict';

var MAX_NUMBER = 100,
    MIN_NUMBER = -100;

module.exports = function(min, max) {
  min = typeof min === 'undefined' ? MIN_NUMBER : min;
  max = typeof max === 'undefined' ? MAX_NUMBER : max;

  return Math.floor(Math.random() * (max - min + 1)) + min;
};
<commit_msg>Shortcut for randomness<commit_after>'use strict';

var MAX_NUMBER = 100,
    MIN_NUMBER = -100;

module.exports = function(min, max) {
  if (typeof min === 'object') {
    max = min.maxLength;
    min = min.minLength;
  }

  min = typeof min === 'undefined' ? MIN_NUMBER : min;
  max = typeof max === 'undefined' ? MAX_NUMBER : max;

  return Math.floor(Math.random() * (max - min + 1)) + min;
};
<|endoftext|>


<commit_before>// ==========================================================================
//                      DG.MapDataConfiguration
//
//  Author:   William Finzer
//
//  Copyright ©2014 Concord Consortium
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================
/* global L */
sc_require('components/graph_map_common/plot_data_configuration');

/** @class  DG.MapDataConfiguration - The object that describes the manner in which attributes are
    assigned to places in a map.

  @extends DG.PlotDataConfiguration
*/
DG.MapDataConfiguration = DG.PlotDataConfiguration.extend(
/** @scope DG.MapDataConfiguration.prototype */
{
  /**
   * It is in initialization that we specialize from base class
   */
  init: function() {

    var attributeDescriptions = {
                                  caption: DG.AttributePlacementDescription.create(),
                                  x: DG.AttributePlacementDescription.create(),
                                  y: DG.AttributePlacementDescription.create(),
                                  legend: DG.AttributePlacementDescription.create(),
                                  area: DG.AttributePlacementDescription.create()
                                },
        tPlace,
        tDefaults = DG.currDocumentController().collectionDefaults(),
        tChildCollectionClient = tDefaults && tDefaults.collectionClient,
        tParentCollectionClient = tDefaults && tDefaults.parentCollectionClient,
        tCaptionName, tLatName, tLongName, tAreaName,
        tCaptionAttr, tLatAttr, tLongAttr, tAreaAttr,
        kLatNames = ['latitude', 'lat', 'Latitude', 'Lat', 'LAT'],
        kLongNames = ['longitude', 'long', 'lng', 'Longitude', 'Long', 'Lng', 'LONG'],
        kAreaNames = ['boundary', 'area', 'polygon', 'Boundary', 'Area', 'Polygon'];

    sc_super();

    /**
        Utility function for use in confuguring the attribute descriptions
        @param  {String}    iAttrPrefix -- {'x','y','legend'}
        @param  {String}    iAttrInfix -- {'X','Y','Legend'}
        @param  {Number}    iNumericRole -- Numeric analysis role
        @param  {Number}    iCategoricalRole -- Categorical analysis role
     */
    var configAttrDesc = function( iAttrPrefix, iAttr, iCollectionClient) {
      var attrDesc = attributeDescriptions[ iAttrPrefix],
          tType;

      DG.assert( attrDesc);

      // Configure the attribute description for the specified default attribute
      if( iAttr) {
        // Must set collection before attribute for attribute stats to be configured properly
        attrDesc.set('collectionClient', iCollectionClient);
        attrDesc.set('attribute', iAttr);
        switch( iAttrPrefix) {
          case 'x':
          case 'y':
            tType = DG.Analysis.EAttributeType.eNumeric;
            break;
          case 'area':
            tType = DG.Analysis.EAttributeType.eBoundary;
            break;
          case 'caption':
            tType = DG.Analysis.EAttributeType.eCategorical;
            break;
        }
        if( tType)
          attrDesc.setPath('attributeStats.attributeType', tType);
      }
      // Null out the attribute description when no map attribute is specified.
      else {
        attrDesc.set('collectionClient', null);
        attrDesc.removeAllAttributes();
      }

      // We must set these up manually, because the infrastructure isn't in place by
      // the time sc_super() (i.e. SC.Object.init()) is called.
      attrDesc.addObserver('collectionClient', this, iAttrPrefix + 'CollectionDidChange');
    }.bind( this);

    var lookForMapAttributes = function( iCollectionClient) {
      var tFoundOne = false,
          tAttrNames = iCollectionClient && iCollectionClient.getAttributeNames();
      if( tAttrNames) {
        tCaptionName = tAttrNames[ 0];
        tCaptionAttr = tCaptionName && iCollectionClient.getAttributeByName( tCaptionName);

        kLatNames.forEach( function( iName) {
          if( tAttrNames.indexOf( iName) >= 0) {
            tLatName = iName;
            tFoundOne = true;
          }
        });
        tLatAttr = tLatName && iCollectionClient.getAttributeByName( tLatName);
        kLongNames.forEach( function( iName) {
          if( tAttrNames.indexOf( iName) >= 0) {
            tLongName = iName;
            tFoundOne = true;
          }
        });
        tLongAttr = tLongName && iCollectionClient.getAttributeByName( tLongName);

        kAreaNames.forEach( function( iName) {
          if( tAttrNames.indexOf( iName) >= 0) {
            tAreaName = iName;
            tFoundOne = true;
          }
        });
        tAreaAttr = tAreaName && iCollectionClient.getAttributeByName( tAreaName);
      }

      configAttrDesc('caption', tCaptionAttr, iCollectionClient);
      configAttrDesc('x', tLongAttr, iCollectionClient);
      configAttrDesc('y', tLatAttr, iCollectionClient);
      configAttrDesc('legend', null, iCollectionClient);
      configAttrDesc('area', tAreaAttr, iCollectionClient);

      return tFoundOne;
    }.bind( this);

    if (!lookForMapAttributes( tChildCollectionClient)) {
      lookForMapAttributes( tParentCollectionClient);
    }

    // Prepare the attributes array. It has as many elements as there are places,
    //  and, initially, those elements are empty arrays.
    this.attributesByPlace = [];
    for( tPlace = 0; tPlace < DG.GraphTypes.EPlace.eNumPlaces; tPlace++)
      this.attributesByPlace[tPlace] = [];

    // Actually, during this coding transition, we're going to stash the previously
    // initialized attribute descriptions in attributesByPlace.
    this.attributesByPlace[ DG.GraphTypes.EPlace.eCaption][0] = attributeDescriptions.caption;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eX][0] = attributeDescriptions.x;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eY][0] = attributeDescriptions.y;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eLegend][0] = attributeDescriptions.legend;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eArea][0] = attributeDescriptions.area;
  },

  /**
   * Override to return use the source that is used by either the area attribute or one of the lat/long attributes.
   * Note that we are assuming that _either_ the area attribute _or_ the xAttribute have a collection client. If
   * they both have collection clients and those are different, this won't be adequate.
   */
  collectionClient: function() {
    var tKeys = ['areaAttributeDescription', 'xAttributeDescription'],
        tSource;
    tKeys.forEach( function( iAttrKey) {
      var tAttrDesc = this.get( iAttrKey);
      if( tAttrDesc && tAttrDesc.collectionClient)
        tSource = tAttrDesc.collectionClient;
    }.bind( this));
    return tSource;
  }.property(),

  /**
   * @property {SC.Array of DG.Case} All cases, both hidden and visible
   */
  allCases: function() {
    var tSource = this.get('collectionClient');
    return tSource ? tSource.getPath('casesController.arrangedObjects') : null;
  }.property(),

  /**
   @property { DG.AttributePlacementDescription }
   */
  areaAttributeDescription: function( iKey, iValue) {
    return this.attributeDescriptionForPlace( iKey, iValue, DG.GraphTypes.EPlace.eArea);
  }.property(),

  areaCollectionDidChange: function() {
    this.notifyPropertyChange('areaCollectionClient');
  },

  areaCollectionClient: function() {
    return this.getPath('areaAttributeDescription.collectionClient');
  }.property('areaAttributeDescription.collectionClient').cacheable(),

  latAttributeID: function() {
    return this.getPath('yAttributeDescription.attributeID');
  }.property('yAttributeDescription.attributeID').cacheable(),

  longAttributeID: function() {
    return this.getPath('xAttributeDescription.attributeID');
  }.property('xAttributeDescription.attributeID').cacheable(),

  hasLatLongAttributes: function() {
    return !SC.none(this.get('latAttributeID')) && !SC.none(this.get('longAttributeID'));
  }.property('latAttributeID', 'longAttributeID').cacheable(),

  areaAttributeID: function() {
    return this.getPath('areaAttributeDescription.attributeID');
  }.property('areaAttributeDescription.attributeID').cacheable(),

  /**
   @property { DG.AttributePlacementDescription }
   */
  captionAttributeDescription: function( iKey, iValue) {
    return this.attributeDescriptionForPlace( iKey, iValue, DG.GraphTypes.EPlace.eCaption);
  }.property(),

  captionCollectionDidChange: function() {
    this.notifyPropertyChange('captionCollectionClient');
  },

  captionCollectionClient: function() {
    return this.getPath('captionAttributeDescription.collectionClient');
  }.property('captionAttributeDescription.collectionClient'),

  captionAttributeID: function() {
    return this.getPath('captionAttributeDescription.attributeID');
  }.property('captionAttributeDescription.attributeID'),

  getLatLongBounds: function() {
    var tLatMinMax = this.getPath('yAttributeDescription.attributeStats.minMax' ),
        tLngMinMax = this.getPath('xAttributeDescription.attributeStats.minMax' ),
        tSouthWest = [tLatMinMax.min, tLngMinMax.min],
        tNorthEast = [tLatMinMax.max, tLngMinMax.max];
    return L.latLngBounds([tSouthWest, tNorthEast]);
  },

  /**
   * If there is an area attribute, go through its values, finding the rectangle that encompases all
   * the coordinates.
   * @returns {*[]}
   */
  getAreaBounds: function() {
    var tCases = this.get('cases'),
        tAreaID = this.get('areaAttributeID'),
        tMinWest = 180, tMaxEast = -180, tMinSouth = 90, tMaxNorth = -90;
    if( !tAreaID)
      return null;

    function processArrayOfCoords( iArrayOfCoords) {
      iArrayOfCoords.forEach( function( iPoint) {
        tMinSouth = Math.min( tMinSouth, iPoint[1]);
        tMaxNorth = Math.max( tMaxNorth, iPoint[1]);
        tMinWest = Math.min( tMinWest, iPoint[0]);
        tMaxEast = Math.max( tMaxEast, iPoint[0]);
      });
    }

    tCases.forEach( function( iCase) {
      try {
        var tFeature = JSON.parse(iCase.getValue(tAreaID)),
            tCoords = tFeature.geometry.coordinates,
            tType = tFeature.geometry.type;
        tCoords.forEach(function (iArray) {
          switch (tType) {
            case 'Polygon':
              processArrayOfCoords(iArray);
              break;
            case 'MultiPolygon':
              iArray.forEach(function (iSubArray) {
                processArrayOfCoords(iSubArray);
              });
              break;
          }
        });
      }
      catch(er) {}
    });

    return L.latLngBounds([[tMinSouth, tMinWest], [tMaxNorth, tMaxEast]]);
  }

});

<commit_msg>Maps will fill with data if there is exactly one data context with GIS-related attributes.<commit_after>// ==========================================================================
//                      DG.MapDataConfiguration
//
//  Author:   William Finzer
//
//  Copyright ©2014 Concord Consortium
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================
/* global L */
sc_require('components/graph_map_common/plot_data_configuration');

/** @class  DG.MapDataConfiguration - The object that describes the manner in which attributes are
    assigned to places in a map.

  @extends DG.PlotDataConfiguration
*/
DG.MapDataConfiguration = DG.PlotDataConfiguration.extend(
/** @scope DG.MapDataConfiguration.prototype */
{
  /**
   * It is in initialization that we specialize from base class
   */
  init: function() {

    var attributeDescriptions = {
                                  caption: DG.AttributePlacementDescription.create(),
                                  x: DG.AttributePlacementDescription.create(),
                                  y: DG.AttributePlacementDescription.create(),
                                  legend: DG.AttributePlacementDescription.create(),
                                  area: DG.AttributePlacementDescription.create()
                                },
        tPlace,
        tChildCollectionClient, tParentCollectionClient,
        tCaptionName, tLatName, tLongName, tAreaName,
        tCaptionAttr, tLatAttr, tLongAttr, tAreaAttr,
        kLatNames = ['latitude', 'lat', 'Latitude', 'Lat', 'LAT'],
        kLongNames = ['longitude', 'long', 'lng', 'Longitude', 'Long', 'Lng', 'LONG'],
        kAreaNames = ['boundary', 'area', 'polygon', 'Boundary', 'Area', 'Polygon'];

    sc_super();

    var findGISCollection = function() {
      var tMapContexts = DG.currDocumentController().get('contexts').filter( function( iContext) {
        return [ iContext.get('childCollection'), iContext.get('parentCollection')].some( function( iCollection) {
          var tAttrNames = (iCollection && iCollection.getAttributeNames()) || [],
              tFoundLat = kLatNames.some(function (iName) {
                return tAttrNames.indexOf(iName) >= 0;
              }),
              tFoundLong = kLongNames.some(function (iName) {
                return tAttrNames.indexOf(iName) >= 0;
              }),
              tFoundArea = kAreaNames.some(function (iName) {
                return tAttrNames.indexOf(iName) >= 0;
              });
          return (tFoundLat && tFoundLong) || tFoundArea;
        });
      });
      if( tMapContexts.length === 1) {
        tChildCollectionClient = tMapContexts[0].get('childCollection');
        tParentCollectionClient = tMapContexts[0].get('parentCollection');
      }
    }.bind( this);

    /**
        Utility function for use in confuguring the attribute descriptions
        @param  {String}    iAttrPrefix -- {'x','y','legend'}
        @param  {String}    iAttrInfix -- {'X','Y','Legend'}
        @param  {Number}    iNumericRole -- Numeric analysis role
        @param  {Number}    iCategoricalRole -- Categorical analysis role
     */
    var configAttrDesc = function( iAttrPrefix, iAttr, iCollectionClient) {
      var attrDesc = attributeDescriptions[ iAttrPrefix],
          tType;

      DG.assert( attrDesc);

      // Configure the attribute description for the specified default attribute
      if( iAttr) {
        // Must set collection before attribute for attribute stats to be configured properly
        attrDesc.set('collectionClient', iCollectionClient);
        attrDesc.set('attribute', iAttr);
        switch( iAttrPrefix) {
          case 'x':
          case 'y':
            tType = DG.Analysis.EAttributeType.eNumeric;
            break;
          case 'area':
            tType = DG.Analysis.EAttributeType.eBoundary;
            break;
          case 'caption':
            tType = DG.Analysis.EAttributeType.eCategorical;
            break;
        }
        if( tType)
          attrDesc.setPath('attributeStats.attributeType', tType);
      }
      // Null out the attribute description when no map attribute is specified.
      else {
        attrDesc.set('collectionClient', null);
        attrDesc.removeAllAttributes();
      }

      // We must set these up manually, because the infrastructure isn't in place by
      // the time sc_super() (i.e. SC.Object.init()) is called.
      attrDesc.addObserver('collectionClient', this, iAttrPrefix + 'CollectionDidChange');
    }.bind( this);

    // TODO: Refactor the following to use some of the techniques above in findGISCollection
    var lookForMapAttributes = function( iCollectionClient) {
      var tFoundOne = false,
          tAttrNames = iCollectionClient && iCollectionClient.getAttributeNames();
      if( tAttrNames) {
        tCaptionName = tAttrNames[ 0];
        tCaptionAttr = tCaptionName && iCollectionClient.getAttributeByName( tCaptionName);

        kLatNames.forEach( function( iName) {
          if( tAttrNames.indexOf( iName) >= 0) {
            tLatName = iName;
            tFoundOne = true;
          }
        });
        tLatAttr = tLatName && iCollectionClient.getAttributeByName( tLatName);
        kLongNames.forEach( function( iName) {
          if( tAttrNames.indexOf( iName) >= 0) {
            tLongName = iName;
            tFoundOne = true;
          }
        });
        tLongAttr = tLongName && iCollectionClient.getAttributeByName( tLongName);

        kAreaNames.forEach( function( iName) {
          if( tAttrNames.indexOf( iName) >= 0) {
            tAreaName = iName;
            tFoundOne = true;
          }
        });
        tAreaAttr = tAreaName && iCollectionClient.getAttributeByName( tAreaName);
      }

      configAttrDesc('caption', tCaptionAttr, iCollectionClient);
      configAttrDesc('x', tLongAttr, iCollectionClient);
      configAttrDesc('y', tLatAttr, iCollectionClient);
      configAttrDesc('legend', null, iCollectionClient);
      configAttrDesc('area', tAreaAttr, iCollectionClient);

      return tFoundOne;
    }.bind( this);

    findGISCollection();

    if (!lookForMapAttributes( tChildCollectionClient)) {
      lookForMapAttributes( tParentCollectionClient);
    }

    // Prepare the attributes array. It has as many elements as there are places,
    //  and, initially, those elements are empty arrays.
    this.attributesByPlace = [];
    for( tPlace = 0; tPlace < DG.GraphTypes.EPlace.eNumPlaces; tPlace++)
      this.attributesByPlace[tPlace] = [];

    // Actually, during this coding transition, we're going to stash the previously
    // initialized attribute descriptions in attributesByPlace.
    this.attributesByPlace[ DG.GraphTypes.EPlace.eCaption][0] = attributeDescriptions.caption;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eX][0] = attributeDescriptions.x;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eY][0] = attributeDescriptions.y;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eLegend][0] = attributeDescriptions.legend;
    this.attributesByPlace[ DG.GraphTypes.EPlace.eArea][0] = attributeDescriptions.area;
  },

  /**
   * Override to return use the source that is used by either the area attribute or one of the lat/long attributes.
   * Note that we are assuming that _either_ the area attribute _or_ the xAttribute have a collection client. If
   * they both have collection clients and those are different, this won't be adequate.
   */
  collectionClient: function() {
    var tKeys = ['areaAttributeDescription', 'xAttributeDescription'],
        tSource;
    tKeys.forEach( function( iAttrKey) {
      var tAttrDesc = this.get( iAttrKey);
      if( tAttrDesc && tAttrDesc.collectionClient)
        tSource = tAttrDesc.collectionClient;
    }.bind( this));
    return tSource;
  }.property(),

  /**
   * @property {SC.Array of DG.Case} All cases, both hidden and visible
   */
  allCases: function() {
    var tSource = this.get('collectionClient');
    return tSource ? tSource.getPath('casesController.arrangedObjects') : null;
  }.property(),

  /**
   @property { DG.AttributePlacementDescription }
   */
  areaAttributeDescription: function( iKey, iValue) {
    return this.attributeDescriptionForPlace( iKey, iValue, DG.GraphTypes.EPlace.eArea);
  }.property(),

  areaCollectionDidChange: function() {
    this.notifyPropertyChange('areaCollectionClient');
  },

  areaCollectionClient: function() {
    return this.getPath('areaAttributeDescription.collectionClient');
  }.property('areaAttributeDescription.collectionClient').cacheable(),

  latAttributeID: function() {
    return this.getPath('yAttributeDescription.attributeID');
  }.property('yAttributeDescription.attributeID').cacheable(),

  longAttributeID: function() {
    return this.getPath('xAttributeDescription.attributeID');
  }.property('xAttributeDescription.attributeID').cacheable(),

  hasLatLongAttributes: function() {
    return !SC.none(this.get('latAttributeID')) && !SC.none(this.get('longAttributeID'));
  }.property('latAttributeID', 'longAttributeID').cacheable(),

  areaAttributeID: function() {
    return this.getPath('areaAttributeDescription.attributeID');
  }.property('areaAttributeDescription.attributeID').cacheable(),

  /**
   @property { DG.AttributePlacementDescription }
   */
  captionAttributeDescription: function( iKey, iValue) {
    return this.attributeDescriptionForPlace( iKey, iValue, DG.GraphTypes.EPlace.eCaption);
  }.property(),

  captionCollectionDidChange: function() {
    this.notifyPropertyChange('captionCollectionClient');
  },

  captionCollectionClient: function() {
    return this.getPath('captionAttributeDescription.collectionClient');
  }.property('captionAttributeDescription.collectionClient'),

  captionAttributeID: function() {
    return this.getPath('captionAttributeDescription.attributeID');
  }.property('captionAttributeDescription.attributeID'),

  getLatLongBounds: function() {
    var tLatMinMax = this.getPath('yAttributeDescription.attributeStats.minMax' ),
        tLngMinMax = this.getPath('xAttributeDescription.attributeStats.minMax' ),
        tSouthWest = [tLatMinMax.min, tLngMinMax.min],
        tNorthEast = [tLatMinMax.max, tLngMinMax.max];
    return L.latLngBounds([tSouthWest, tNorthEast]);
  },

  /**
   * If there is an area attribute, go through its values, finding the rectangle that encompases all
   * the coordinates.
   * @returns {*[]}
   */
  getAreaBounds: function() {
    var tCases = this.get('cases'),
        tAreaID = this.get('areaAttributeID'),
        tMinWest = 180, tMaxEast = -180, tMinSouth = 90, tMaxNorth = -90;
    if( !tAreaID)
      return null;

    function processArrayOfCoords( iArrayOfCoords) {
      iArrayOfCoords.forEach( function( iPoint) {
        tMinSouth = Math.min( tMinSouth, iPoint[1]);
        tMaxNorth = Math.max( tMaxNorth, iPoint[1]);
        tMinWest = Math.min( tMinWest, iPoint[0]);
        tMaxEast = Math.max( tMaxEast, iPoint[0]);
      });
    }

    tCases.forEach( function( iCase) {
      try {
        var tFeature = JSON.parse(iCase.getValue(tAreaID)),
            tCoords = tFeature.geometry.coordinates,
            tType = tFeature.geometry.type;
        tCoords.forEach(function (iArray) {
          switch (tType) {
            case 'Polygon':
              processArrayOfCoords(iArray);
              break;
            case 'MultiPolygon':
              iArray.forEach(function (iSubArray) {
                processArrayOfCoords(iSubArray);
              });
              break;
          }
        });
      }
      catch(er) {}
    });

    return L.latLngBounds([[tMinSouth, tMinWest], [tMaxNorth, tMaxEast]]);
  }

});

<|endoftext|>


<commit_before>import React from "react"
import { connect } from "react-redux"
import { TokenSelectorView } from '../../components/CommonElement'
import { getTranslate } from 'react-localize-redux';

@connect((store, props) => {
  var listToken = []
  Object.values(props.listItem).map((value, i) => {
    listToken.push(value)
  })

  return {
    account: store.account.account,
    focusItem: props.focusItem,
    listToken: listToken,
    type: props.type,
    chooseToken: props.chooseToken,
    translate: getTranslate(store.locale),
    banToken: props.banToken,
    isFixToken: props.isFixToken,
    analytics: store.global.analytics
  }
})

export default class TokenSelector extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      searchWord: "",
      isScroll: false,
      tokenNumberLimit: 20,
      isLoadAllTokens: false,
    }
  }

  setLoadAllTokens = () => {
    this.setState({ isLoadAllTokens: true })
  }

  changeWord = (e) => {
    var value = e.target.value.toLowerCase()
    this.setState({ searchWord: value })
  }

  showTokens = (e) => {
    this.setState({ open: true })
  }

  hideTokens = (e) => {
    this.setState({
      open: false,
      searchWord: "",
    })
  }

  selectItem = (event, symbol, address) => {
    this.props.chooseToken(symbol, address, this.props.type)
  }

  render() {
    return (
      <TokenSelectorView
        account={this.props.account}
        open={this.state.open}
        searchWord={this.state.searchWord}
        tokens={this.props.listToken}
        focusItem={this.props.focusItem}
        toggleOpen={this.toggleOpen}
        changeWord={this.changeWord}
        selectItem={this.selectItem}
        translate={this.props.translate}
        showTokens={this.showTokens}
        hideTokens={this.hideTokens}
        type={this.props.type}
        banToken={this.props.banToken}
        isFixToken={this.props.isFixToken}
        analytics={this.props.analytics}
        onListScroll = {this.setLoadAllTokens}
        screen={this.props.screen}
        tokenNumberLimit={this.state.tokenNumberLimit}
        isLoadAllTokens={this.state.isLoadAllTokens}
      />
    )
  }
}
<commit_msg>Remove unused state<commit_after>import React from "react"
import { connect } from "react-redux"
import { TokenSelectorView } from '../../components/CommonElement'
import { getTranslate } from 'react-localize-redux';

@connect((store, props) => {
  var listToken = []
  Object.values(props.listItem).map((value, i) => {
    listToken.push(value)
  })

  return {
    account: store.account.account,
    focusItem: props.focusItem,
    listToken: listToken,
    type: props.type,
    chooseToken: props.chooseToken,
    translate: getTranslate(store.locale),
    banToken: props.banToken,
    isFixToken: props.isFixToken,
    analytics: store.global.analytics
  }
})

export default class TokenSelector extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      searchWord: "",
      tokenNumberLimit: 20,
      isLoadAllTokens: false,
    }
  }

  setLoadAllTokens = () => {
    this.setState({ isLoadAllTokens: true })
  }

  changeWord = (e) => {
    var value = e.target.value.toLowerCase()
    this.setState({ searchWord: value })
  }

  showTokens = (e) => {
    this.setState({ open: true })
  }

  hideTokens = (e) => {
    this.setState({
      open: false,
      searchWord: "",
    })
  }

  selectItem = (event, symbol, address) => {
    this.props.chooseToken(symbol, address, this.props.type)
  }

  render() {
    return (
      <TokenSelectorView
        account={this.props.account}
        open={this.state.open}
        searchWord={this.state.searchWord}
        tokens={this.props.listToken}
        focusItem={this.props.focusItem}
        toggleOpen={this.toggleOpen}
        changeWord={this.changeWord}
        selectItem={this.selectItem}
        translate={this.props.translate}
        showTokens={this.showTokens}
        hideTokens={this.hideTokens}
        type={this.props.type}
        banToken={this.props.banToken}
        isFixToken={this.props.isFixToken}
        analytics={this.props.analytics}
        onListScroll = {this.setLoadAllTokens}
        screen={this.props.screen}
        tokenNumberLimit={this.state.tokenNumberLimit}
        isLoadAllTokens={this.state.isLoadAllTokens}
      />
    )
  }
}
<|endoftext|>


<commit_before>if (typeof define !== 'function') { var define = require('amdefine')(module) }

define([
  '../shortcut-manager',
  '../keyboard-util',
  './util'
],function(
  ShortcutManager,
  keyboardUtil,
  util
) {

  var noop = function() {};
  var toKeyCodes = util.toKeyCodes;

  describe('tests suite', function() {
    it('should execute', function() {
      expect(true).toBe(true);
    });
  });

  describe('keyboard shortcut', function() {
    var callback;
    beforeEach(function() {
      callback = jasmine.createSpy('callback');
    });
    it('with one key should call according callback', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('with two keys should call according callback', function() {
      var shortcut = ['Meta', 'I', 'I'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('multiple registered shortcuts should fire the right one', function() {
      var shortcut = ['Meta', 'I', 'I'];
      var unusedShortcut = ['Meta', 'S'];
      mapShortcuts([
        [unusedShortcut, noop],
        [shortcut, callback]
      ]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('dont fire before Meta-keyUp', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeys(toKeyCodes(shortcut));
      expect(callback).not.toHaveBeenCalled();
    });
    it('press shortcut twice', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback.callCount).toBe(2);
    });
    it('press part of a shortcut and a shortcut afterwards', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes([shortcut[0]]));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });

    it('NOT starting with `Meta`', function() {
      var shortcut = ['Ctrl', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('overlapping shortcuts', function() {
      var shortcut = ['Meta', 'Ctrl', 'S'];
      var shortcut1 = ['Ctrl', 'S'];
      mapShortcuts([
        [shortcut, callback],
        [shortcut1, noop]
      ]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('overlapping shortcuts and invalid keys before', function() {
      var shortcut = ['Meta', 'Ctrl', 'S'];
      var shortcut1 = ['Ctrl', 'S'];
      mapShortcuts([
        [shortcut, callback],
        [shortcut1, noop]
      ]);
      pressKeysAndFinalKeyUp(toKeyCodes(['A', 'B']));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });

    it('invalid shortcut followed by valid shortcut, should fire callback', function() {
      var shortcut = ['Meta', 'I', 'I'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(['A']));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
  });

  // test utils

  function mapShortcuts(shortcuts) {
    var manager = new ShortcutManager();
    shortcuts.forEach(function(shortcut) {
      manager.registerShortcut(shortcut[0], shortcut[1]);
    });
  }

  var keyDownListeners;
  var keyUpListeners;

  beforeEach(function() {
    // Initialize for each test.
    keyDownListeners = [];
    keyUpListeners = [];
  });

  spyOn(keyboardUtil, 'addKeyDownListener').andCallFake(function(fn) {
    keyDownListeners.push(fn);
  });
  spyOn(keyboardUtil, 'addKeyUpListener').andCallFake(function(fn) {
    keyUpListeners.push(fn);
  });

  function pressKeys(keys) {
    // The first key is (normally) the Meta key, don't fire keyUp yet,
    // fire it only at the end of it all.
    var firstKey = keys[0];
    keyDownListeners[0](firstKey);

    // Fire all keyDowns and keyUps.
    keys.slice(1).forEach(function(key) {
      keyDownListeners[0](key);
      keyUpListeners[0](key);
    });
    return firstKey;
  }

  function finalKeyUp(metaKey) {
    // The final keyUp (of the Meta key).
    keyUpListeners[0](metaKey);
  }

  function pressKeysAndFinalKeyUp(keys) {
    var firstKey = pressKeys(keys);
    finalKeyUp(firstKey);
  }

});
<commit_msg>Don't spy on keyboardUtil methods globally.<commit_after>if (typeof define !== 'function') { var define = require('amdefine')(module) }

define([
  '../shortcut-manager',
  '../keyboard-util',
  './util'
],function(
  ShortcutManager,
  keyboardUtil,
  util
) {

  var noop = function() {};
  var toKeyCodes = util.toKeyCodes;

  describe('tests suite', function() {
    it('should execute', function() {
      expect(true).toBe(true);
    });
  });

  describe('keyboard shortcut', function() {
    var callback;
    beforeEach(function() {
      callback = jasmine.createSpy('callback');
    });
    it('with one key should call according callback', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('with two keys should call according callback', function() {
      var shortcut = ['Meta', 'I', 'I'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('multiple registered shortcuts should fire the right one', function() {
      var shortcut = ['Meta', 'I', 'I'];
      var unusedShortcut = ['Meta', 'S'];
      mapShortcuts([
        [unusedShortcut, noop],
        [shortcut, callback]
      ]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('dont fire before Meta-keyUp', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeys(toKeyCodes(shortcut));
      expect(callback).not.toHaveBeenCalled();
    });
    it('press shortcut twice', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback.callCount).toBe(2);
    });
    it('press part of a shortcut and a shortcut afterwards', function() {
      var shortcut = ['Meta', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes([shortcut[0]]));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });

    it('NOT starting with `Meta`', function() {
      var shortcut = ['Ctrl', 'S'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('overlapping shortcuts', function() {
      var shortcut = ['Meta', 'Ctrl', 'S'];
      var shortcut1 = ['Ctrl', 'S'];
      mapShortcuts([
        [shortcut, callback],
        [shortcut1, noop]
      ]);
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });
    it('overlapping shortcuts and invalid keys before', function() {
      var shortcut = ['Meta', 'Ctrl', 'S'];
      var shortcut1 = ['Ctrl', 'S'];
      mapShortcuts([
        [shortcut, callback],
        [shortcut1, noop]
      ]);
      pressKeysAndFinalKeyUp(toKeyCodes(['A', 'B']));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });

    it('invalid shortcut followed by valid shortcut, should fire callback', function() {
      var shortcut = ['Meta', 'I', 'I'];
      mapShortcuts([[shortcut, callback]]);
      pressKeysAndFinalKeyUp(toKeyCodes(['A']));
      pressKeysAndFinalKeyUp(toKeyCodes(shortcut));
      expect(callback).toHaveBeenCalled();
    });

    // test utils

    function mapShortcuts(shortcuts) {
      var manager = new ShortcutManager();
      shortcuts.forEach(function(shortcut) {
        manager.registerShortcut(shortcut[0], shortcut[1]);
      });
    }

    var keyDownListeners;
    var keyUpListeners;

    beforeEach(function() {
      // Initialize for each test.
      keyDownListeners = [];
      keyUpListeners = [];

      spyOn(keyboardUtil, 'addKeyDownListener').andCallFake(function(fn) {
        keyDownListeners.push(fn);
      });
      spyOn(keyboardUtil, 'addKeyUpListener').andCallFake(function(fn) {
        keyUpListeners.push(fn);
      });
    });

    function pressKeys(keys) {
      // The first key is (normally) the Meta key, don't fire keyUp yet,
      // fire it only at the end of it all.
      var firstKey = keys[0];
      keyDownListeners[0](firstKey);

      // Fire all keyDowns and keyUps.
      keys.slice(1).forEach(function(key) {
        keyDownListeners[0](key);
        keyUpListeners[0](key);
      });
      return firstKey;
    }

    function finalKeyUp(metaKey) {
      // The final keyUp (of the Meta key).
      keyUpListeners[0](metaKey);
    }

    function pressKeysAndFinalKeyUp(keys) {
      var firstKey = pressKeys(keys);
      finalKeyUp(firstKey);
    }

  });

});
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var mm = require('micromatch');

/**
 * Extend `utils` methods in other files
 */

var utils = require('export-files')(__dirname);

/**
 * Read a file
 */

utils.readFile = function readFile(fp) {
  return fs.readFileSync(fp, 'utf8');
};

/**
 * Write a file
 */

utils.writeFile = function writeFile(fp, str) {
  return fs.writeFileSync(fp, str);
};

/**
 * Creates a matching function to use against
 * the list of given files.
 */

utils.match = function match(files) {
  return function(pattern, options) {
    return mm(files, pattern, options);
  };
};

/**
 * Read a file
 */

utils.tryRead = function tryRead(fp) {
  try {
    return fs.readFileSync(fp, 'utf8');
  } catch(err) {}
  return null;
};

/**
 * Read a file
 */

utils.tryReadJson = function tryReadJson(fp) {
  try {
    return JSON.parse(fs.readFileSync(fp, 'utf8'));
  } catch(err) {}
  return null;
};

/**
 * Try to read a directory of files. Silently catches
 * any errors and returns an empty array.
 */

utils.tryStat = function tryStat(fp) {
  try {
    return fs.statSync(fp);
  } catch (err) {}
  return [];
};

/**
 * Try to read a directory of files. Silently catches
 * any errors and returns an empty array.
 */

utils.tryReaddir = function tryReaddir(fp) {
  try {
    return fs.readdirSync(fp);
  } catch (err) {}
  return [];
};

/**
 * Expose `utils`
 */

module.exports = utils;
<commit_msg>adds tryResolve<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var mm = require('micromatch');

/**
 * Extend `utils` methods in other files
 */

var utils = require('export-files')(__dirname);

/**
 * Read a file
 */

utils.readFile = function readFile(fp) {
  return fs.readFileSync(fp, 'utf8');
};

/**
 * Write a file
 */

utils.writeFile = function writeFile(fp, str) {
  return fs.writeFileSync(fp, str);
};

/**
 * Creates a matching function to use against
 * the list of given files.
 */

utils.match = function match(files) {
  return function(pattern, options) {
    return mm(files, pattern, options);
  };
};

/**
 * Try to resolve the given path, fail silently
 */

utils.tryResolve = function tryResolve(fp) {
  try {
    return require.resolve(fp);
  } catch(err) {}
  return [];
};

/**
 * Read a file
 */

utils.tryRead = function tryRead(fp) {
  try {
    return fs.readFileSync(fp, 'utf8');
  } catch(err) {}
  return null;
};

/**
 * Read a file
 */

utils.tryReadJson = function tryReadJson(fp) {
  try {
    return JSON.parse(fs.readFileSync(fp, 'utf8'));
  } catch(err) {}
  return null;
};

/**
 * Try to read a directory of files. Silently catches
 * any errors and returns an empty array.
 */

utils.tryStat = function tryStat(fp) {
  try {
    return fs.statSync(fp);
  } catch (err) {}
  return [];
};

/**
 * Try to read a directory of files. Silently catches
 * any errors and returns an empty array.
 */

utils.tryReaddir = function tryReaddir(fp) {
  try {
    return fs.readdirSync(fp);
  } catch (err) {}
  return [];
};

/**
 * Expose `utils`
 */

module.exports = utils;
<|endoftext|>