<commit_before>(function () {
  'use strict';

  describe('ProviderController', function () {
    var ctrl,
      $controller,
      dependencies,
      $rootScope,
      $ionicLoading,
      ProviderService,
      deferCreateProvider,
      deferStateGo,
      $state,
      $auth,
      $ionicPopup,
      $ionicScrollDelegate,
      $translate,
      stateRedirect,
      deferTranslate;

    beforeEach(module('porttare.controllers'));

    beforeEach(inject(
      function ($q,
        _$controller_,
        _$rootScope_) {

        deferCreateProvider = $q.defer();
        deferStateGo = $q.defer();
        deferTranslate = $q.defer();
        $controller = _$controller_;
        $rootScope = _$rootScope_;
        $ionicLoading = {
          show: sinon.stub(),
          hide: sinon.stub()
        };
        $ionicScrollDelegate = {
          scrollTop: sinon.stub()
        };
        $state = {
          go: sinon.stub().returns(deferStateGo.promise)
        };
        $ionicPopup = {
          alert: sinon.stub()
        };
        $translate = sinon.stub().returns(deferTranslate.promise);
        ProviderService = {
          createNewProvider: sinon.stub().returns(deferCreateProvider.promise)
        };
        $auth = {
          user: {name:'', email:''}
        };
        stateRedirect = 'provider.items.index';
      })
    );

    describe('Create provider', function () {
      beforeEach(function () {
        dependencies = {
          $ionicLoading: $ionicLoading,
          ProviderService: ProviderService,
          $ionicPopup: $ionicPopup,
          $state: $state,
          $auth: $auth,
          $translate: $translate,
          $ionicScrollDelegate: $ionicScrollDelegate
        };

        ctrl = $controller('ProviderController', dependencies);
      });

      beforeEach(inject(function () {
        ctrl.step = 2;
        ctrl.provider = {'ruc':'222222222','razon_social':'Movvigo','nombre_establecimiento':'Movvigo','actividad_economica':'Gasdro','representante_legal':'Movvigo','telefono':'6666666666','email':'something@movvigo.com','website':'www.moviggo.com'};
        ctrl.matrizProvider = {'direccion':'Aqui','hora_de_apertura':'1899-12-31T11:28:00.000Z','hora_de_cierre':'1899-12-31T15:28:00.000Z','inicio_de_labores':{'label':'Lunes','name':'mon','$$hashKey':'object:159'},'final_de_labores':{'label':'Domingo','name':'sun','$$hashKey':'object:165'},'telefono':'666666666'};
        ctrl.submit();
      }));

      it('name and email should exist in authenticated user', function () {
        expect($auth.user.name).to.exist; //jshint ignore:line
        expect($auth.user.email).to.exist; //jshint ignore:line
      });

      it('legal representative and email  should not be empty', function () {
        chai.assert.isNotNull(ctrl.provider.representante_legal, 'exists!'); //jshint ignore:line
        chai.assert.isNotNull(ctrl.provider.email, 'exists!');
      });

      it('ionicLoading.show should be called', function () {
        sinon.assert.calledOnce($ionicLoading.show);
      });

      it('if successful, ionicLoading.hide should be called', function () {
        deferCreateProvider.resolve({provider_profile: {}}); //jshint ignore:line
        $rootScope.$digest();
        sinon.assert.calledOnce($ionicLoading.hide);
      });

      it('if successful, should change state', function () {
        deferCreateProvider.resolve({provider_profile: {}}); //jshint ignore:line
        $rootScope.$digest();
        sinon.assert.alwaysCalledWithExactly($state.go, stateRedirect);
      });

      it('if successful, should show a alert', function () {
        deferCreateProvider.resolve({provider_profile: {}}); //jshint ignore:line
        $rootScope.$digest();
        deferStateGo.resolve();
        $rootScope.$digest();
        sinon.assert.calledOnce($ionicPopup.alert);
      });

      it('if unsuccessful, should show first template', function () {
        deferCreateProvider.reject({ data: { error: 'error' } });
        $rootScope.$digest();
        expect(ctrl.step).to.be.equal(1);
      });

    });
  });
})();
<commit_msg>revise specs<commit_after>(function () {
  'use strict';

  describe('ProviderController', function () {
    var ctrl,
      $controller,
      dependencies,
      $rootScope,
      $ionicLoading,
      ProviderService,
      deferCreateProvider,
      deferStateGo,
      $state,
      $auth,
      $filter,
      $ionicPopup,
      $ionicScrollDelegate,
      $translate,
      stateRedirect,
      deferTranslate;

    beforeEach(module('porttare.controllers'));
    beforeEach(module('porttare.filters'));

    beforeEach(inject(
      function ($q,
        _$filter_,
        _$controller_,
        _$rootScope_) {

        $filter = _$filter_;
        deferCreateProvider = $q.defer();
        deferStateGo = $q.defer();
        deferTranslate = $q.defer();
        $controller = _$controller_;
        $rootScope = _$rootScope_;
        $ionicLoading = {
          show: sinon.stub(),
          hide: sinon.stub()
        };
        $ionicScrollDelegate = {
          scrollTop: sinon.stub()
        };
        $state = {
          go: sinon.stub().returns(deferStateGo.promise)
        };
        $ionicPopup = {
          alert: sinon.stub()
        };
        $translate = sinon.stub().returns(deferTranslate.promise);
        ProviderService = {
          createNewProvider: sinon.stub().returns(deferCreateProvider.promise)
        };
        $auth = {
          user: {name:'', email:''}
        };
        stateRedirect = 'provider.items.index';
      })
    );

    describe('Create provider', function () {
      beforeEach(function () {
        dependencies = {
          $ionicLoading: $ionicLoading,
          ProviderService: ProviderService,
          $ionicPopup: $ionicPopup,
          $state: $state,
          $auth: $auth,
          $filter: $filter,
          $translate: $translate,
          $ionicScrollDelegate: $ionicScrollDelegate
        };

        ctrl = $controller('ProviderController', dependencies);
      });

      beforeEach(inject(function () {
        ctrl.step = 2;
        ctrl.provider = {'ruc':'222222222','razon_social':'Movvigo','nombre_establecimiento':'Movvigo','actividad_economica':'Gasdro','representante_legal':'Movvigo','telefono':'6666666666','email':'something@movvigo.com','website':'www.moviggo.com'};
        ctrl.matrizProvider = {'direccion':'Aqui','hora_de_apertura':'1899-12-31T11:28:00.000Z','hora_de_cierre':'1899-12-31T15:28:00.000Z','inicio_de_labores':{'label':'Lunes','name':'mon','$$hashKey':'object:159'},'final_de_labores':{'label':'Domingo','name':'sun','$$hashKey':'object:165'},'telefono':'666666666'};
        ctrl.submit();
      }));

      it('name and email should exist in authenticated user', function () {
        expect($auth.user.name).to.exist; //jshint ignore:line
        expect($auth.user.email).to.exist; //jshint ignore:line
      });

      it('legal representative and email  should not be empty', function () {
        chai.assert.isNotNull(ctrl.provider.representante_legal, 'exists!'); //jshint ignore:line
        chai.assert.isNotNull(ctrl.provider.email, 'exists!');
      });

      it('ionicLoading.show should be called', function () {
        sinon.assert.calledOnce($ionicLoading.show);
      });

      it('if successful, ionicLoading.hide should be called', function () {
        deferCreateProvider.resolve({provider_profile: {}}); //jshint ignore:line
        $rootScope.$digest();
        sinon.assert.calledOnce($ionicLoading.hide);
      });

      it('if successful, should change state', function () {
        deferCreateProvider.resolve({provider_profile: {}}); //jshint ignore:line
        $rootScope.$digest();
        sinon.assert.alwaysCalledWithExactly($state.go, stateRedirect);
      });

      it('if successful, should show a alert', function () {
        deferCreateProvider.resolve({provider_profile: {}}); //jshint ignore:line
        $rootScope.$digest();
        deferStateGo.resolve();
        $rootScope.$digest();
        sinon.assert.calledOnce($ionicPopup.alert);
      });

      it('if unsuccessful, should show first template', function () {
        deferCreateProvider.reject({ data: { error: 'error' } });
        $rootScope.$digest();
        expect(ctrl.step).to.be.equal(1);
      });

    });
  });
})();
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Francisco Salavert (ICM-CIPF)
 * Copyright (c) 2012 Ruben Sanchez (ICM-CIPF)
 * Copyright (c) 2012 Ignacio Medina (ICM-CIPF)
 *
 * This file is part of JS Common Libs.
 *
 * JS Common Libs is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * JS Common Libs is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JS Common Libs. If not, see <http://www.gnu.org/licenses/>.
 */

function SequenceAdapter(args) {

    _.extend(this, Backbone.Events);

    this.id = Utils.genId("TrackListPanel");

    //set default args
    this.host;
    this.version;
    this.gzip = true;

    //set instantiation args, must be last
    _.extend(this, args);

    this.sequence = {};
    this.start = {};
    this.end = {};

    this.on(this.handlers);
}

SequenceAdapter.prototype.clearData = function () {
    this.sequence = {};
    this.start = {};
    this.end = {};
};

SequenceAdapter.prototype.getData = function (args) {
    var _this = this;

    this.sender = args.sender;
    var region = args.region;
    var chromosome = region.chromosome;

    region.start = (region.start < 1) ? 1 : region.start;
    region.end = (region.end > 300000000) ? 300000000 : region.end;

    //clean when the new position is too far from current
    // if (region.start < this.start[chromosome] - 5000 || region.end > this.end[chromosome] + 5000) {
    //     this.clearData();
    // }

    var params = {};
    _.extend(params, this.params);

    var queryString = this._getSequenceQuery(region);

    if (queryString != "") {

        CellBaseManager.get({
            host: this.host,
            version: this.version,
            species: this.species,
            category: this.category,
            subCategory: this.subCategory,
            query: queryString,
            resource: this.resource,
            params: params,
            success: function (data) {
                _this._processSequenceQuery(data, true);
            }
        });

    } else {
        if (this.sender != "move") {
            this.trigger('data:ready', {
                items: {
                    sequence: this.sequence[chromosome],
                    start: this.start[chromosome],
                    end: this.end[chromosome]
                },
                params: params,
                sender: this
            });
        }
    }

};

SequenceAdapter.prototype._getSequenceQuery = function (region) {
    var _this = this;
    var chromosome = region.chromosome;

    var s, e, query, querys = [];
    if (_this.start[chromosome] == null && _this.end[chromosome] == null) {
        //args.start -= 100;
        //args.end += 100;
        _this.start[chromosome] = region.start;
        _this.end[chromosome] = region.end;
        s = region.start;
        e = region.end;
        query = chromosome + ":" + s + "-" + e;
        querys.push(query);
    } else {
        if (region.start < _this.start[chromosome]) {
            s = region.start;
            e = _this.start[chromosome] - 1;
            e = (e < 1) ? region.end = 1 : e;
            _this.start[chromosome] = s;
            query = region.chromosome + ":" + s + "-" + e;
            querys.push(query);
        }
        if (region.end > _this.end[chromosome]) {
            e = region.end;
            s = _this.end[chromosome] + 1;
            _this.end[chromosome] = e;
            query = region.chromosome + ":" + s + "-" + e;
            querys.push(query);
        }
    }
    return querys.toString();
};

SequenceAdapter.prototype._processSequenceQuery = function (data, throwNotify) {
    var _this = this;
    var params = data.params;

    for (var i = 0; i < data.response.length; i++) {
        var queryResponse = data.response[i];
        var splitDots = queryResponse.id.split(":");
        var splitDash = splitDots[1].split("-");
        var queryStart = parseInt(splitDash[0]);
        var queryEnd = parseInt(splitDash[1]);

        var queryId = queryResponse.id;
        var seqResponse = queryResponse.result[0];

        var chromosome = seqResponse.chromosome;
        if (typeof chromosome === 'undefined') {
            chromosome = seqResponse.sequenceName;
        }

        if (this.sequence[chromosome] == null) {
            this.sequence[chromosome] = seqResponse.sequence;
        } else {
            if (queryStart == this.start[chromosome]) {
                this.sequence[chromosome] = seqResponse.sequence + this.sequence[chromosome];
            } else {
                this.sequence[chromosome] = this.sequence[chromosome] + seqResponse.sequence;
            }
        }

        if (this.sender == "move" && throwNotify == true) {
            this.trigger('data:ready', {
                items: {
                    sequence: seqResponse.sequence,
                    start: queryStart,
                    end: queryEnd
                },
                params: params,
                sender: this
            });
        }
    }

    if (this.sender != "move" && throwNotify == true) {
        this.trigger('data:ready', {
            items: {
                sequence: this.sequence[chromosome],
                start: this.start[chromosome],
                end: this.end[chromosome]
            },
            params: params,
            sender: this
        });
    }
};

//Used by bam to get the mutations
SequenceAdapter.prototype.getNucleotidByPosition = function (args) {
    var _this = this;
    if (args.start > 0 && args.end > 0) {
        var queryString = this._getSequenceQuery(args);

        var chromosome = args.chromosome;

        if (queryString != "") {
            var data = CellBaseManager.get({
                host: this.host,
                version: this.version,
                species: this.species,
                category: this.category,
                subCategory: this.subCategory,
                query: queryString,
                resource: this.resource,
                params: this.params,
                async: false
            });
            _this._processSequenceQuery(data);
        }
        if (this.sequence[chromosome] != null) {
            var referenceSubStr = this.sequence[chromosome].substr((args.start - this.start[chromosome]), 1);
            return referenceSubStr;
        } else {
            console.log("SequenceRender: this.sequence[chromosome] is undefined");
            return "";
        }
    }
};
SequenceAdapter.prototype.getNucleotidsByRegion = function (args) {
    var region = new Region(args);
    var _this = this;
    if (args.start > 0 && args.end > 0) {
        var queryString = this._getSequenceQuery(args);

        var chromosome = args.chromosome;

        if (queryString != "") {
            var data = CellBaseManager.get({
                host: this.host,
                version: this.version,
                species: this.species,
                category: this.category,
                subCategory: this.subCategory,
                query: queryString,
                resource: this.resource,
                params: this.params,
                async: false
            });
            _this._processSequenceQuery(data);
        }
        if (this.sequence[chromosome] != null) {
            var referenceSubStr = this.sequence[chromosome].substr((args.start - this.start[chromosome]), region.length());
            return referenceSubStr;
        } else {
            console.log("SequenceRender: this.sequence[chromosome] is undefined");
            return "";
        }
    }
};<commit_msg>sequence adapter fix<commit_after>/*
 * Copyright (c) 2012 Francisco Salavert (ICM-CIPF)
 * Copyright (c) 2012 Ruben Sanchez (ICM-CIPF)
 * Copyright (c) 2012 Ignacio Medina (ICM-CIPF)
 *
 * This file is part of JS Common Libs.
 *
 * JS Common Libs is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * JS Common Libs is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JS Common Libs. If not, see <http://www.gnu.org/licenses/>.
 */

function SequenceAdapter(args) {

    _.extend(this, Backbone.Events);

    this.id = Utils.genId("TrackListPanel");

    //set default args
    this.host;
    this.version;
    this.gzip = true;

    //set instantiation args, must be last
    _.extend(this, args);

    this.sequence = {};
    this.start = {};
    this.end = {};

    this.on(this.handlers);
}

SequenceAdapter.prototype.clearData = function () {
    this.sequence = {};
    this.start = {};
    this.end = {};
};

SequenceAdapter.prototype.getData = function (args) {
    var _this = this;

    this.sender = args.sender;
    var region = args.region;
    var chromosome = region.chromosome;

    region.start = (region.start < 1) ? 1 : region.start;
    region.end = (region.end > 300000000) ? 300000000 : region.end;

    //clean when the new position is too far from current
    if (region.start < this.start[chromosome] - 5000 || region.end > this.end[chromosome] + 5000) {
        this.clearData();
    }

    var params = {};
    _.extend(params, this.params);

    var queryString = this._getSequenceQuery(region);

    if (queryString != "") {

        CellBaseManager.get({
            host: this.host,
            version: this.version,
            species: this.species,
            category: this.category,
            subCategory: this.subCategory,
            query: queryString,
            resource: this.resource,
            params: params,
            success: function (data) {
                _this._processSequenceQuery(data, true);
            }
        });

    } else {
        if (this.sender != "move") {
            this.trigger('data:ready', {
                items: {
                    sequence: this.sequence[chromosome],
                    start: this.start[chromosome],
                    end: this.end[chromosome]
                },
                params: params,
                sender: this
            });
        }
    }

};

SequenceAdapter.prototype._getSequenceQuery = function (region) {
    var _this = this;
    var chromosome = region.chromosome;

    var s, e, query, querys = [];
    if (_this.start[chromosome] == null && _this.end[chromosome] == null) {
        //args.start -= 100;
        //args.end += 100;
        _this.start[chromosome] = region.start;
        _this.end[chromosome] = region.end;
        s = region.start;
        e = region.end;
        query = chromosome + ":" + s + "-" + e;
        querys.push(query);
    } else {
        if (region.start < _this.start[chromosome]) {
            s = region.start;
            e = _this.start[chromosome] - 1;
            e = (e < 1) ? region.end = 1 : e;
            _this.start[chromosome] = s;
            query = region.chromosome + ":" + s + "-" + e;
            querys.push(query);
        }
        if (region.end > _this.end[chromosome]) {
            e = region.end;
            s = _this.end[chromosome] + 1;
            _this.end[chromosome] = e;
            query = region.chromosome + ":" + s + "-" + e;
            querys.push(query);
        }
    }
    return querys.toString();
};

SequenceAdapter.prototype._processSequenceQuery = function (data, throwNotify) {
    var _this = this;
    var params = data.params;

    for (var i = 0; i < data.response.length; i++) {
        var queryResponse = data.response[i];
        var splitDots = queryResponse.id.split(":");
        var splitDash = splitDots[1].split("-");
        var queryStart = parseInt(splitDash[0]);
        var queryEnd = parseInt(splitDash[1]);

        var queryId = queryResponse.id;
        var seqResponse = queryResponse.result[0];

        var chromosome = seqResponse.chromosome;
        if (typeof chromosome === 'undefined') {
            chromosome = seqResponse.sequenceName;
        }

        if (this.sequence[chromosome] == null) {
            this.sequence[chromosome] = seqResponse.sequence;
        } else {
            if (queryStart == this.start[chromosome]) {
                this.sequence[chromosome] = seqResponse.sequence + this.sequence[chromosome];
            } else {
                this.sequence[chromosome] = this.sequence[chromosome] + seqResponse.sequence;
            }
        }

        if (this.sender == "move" && throwNotify == true) {
            this.trigger('data:ready', {
                items: {
                    sequence: seqResponse.sequence,
                    start: queryStart,
                    end: queryEnd
                },
                params: params,
                sender: this
            });
        }
    }

    if (this.sender != "move" && throwNotify == true) {
        this.trigger('data:ready', {
            items: {
                sequence: this.sequence[chromosome],
                start: this.start[chromosome],
                end: this.end[chromosome]
            },
            params: params,
            sender: this
        });
    }
};

//Used by bam to get the mutations
SequenceAdapter.prototype.getNucleotidByPosition = function (args) {
    var _this = this;
    if (args.start > 0 && args.end > 0) {
        var queryString = this._getSequenceQuery(args);

        var chromosome = args.chromosome;

        if (queryString != "") {
            var data = CellBaseManager.get({
                host: this.host,
                version: this.version,
                species: this.species,
                category: this.category,
                subCategory: this.subCategory,
                query: queryString,
                resource: this.resource,
                params: this.params,
                async: false
            });
            _this._processSequenceQuery(data);
        }
        if (this.sequence[chromosome] != null) {
            var referenceSubStr = this.sequence[chromosome].substr((args.start - this.start[chromosome]), 1);
            return referenceSubStr;
        } else {
            console.log("SequenceRender: this.sequence[chromosome] is undefined");
            return "";
        }
    }
};
SequenceAdapter.prototype.getNucleotidsByRegion = function (args) {
    var region = new Region(args);
    var _this = this;
    if (args.start > 0 && args.end > 0) {
        var queryString = this._getSequenceQuery(args);

        var chromosome = args.chromosome;

        if (queryString != "") {
            var data = CellBaseManager.get({
                host: this.host,
                version: this.version,
                species: this.species,
                category: this.category,
                subCategory: this.subCategory,
                query: queryString,
                resource: this.resource,
                params: this.params,
                async: false
            });
            _this._processSequenceQuery(data);
        }
        if (this.sequence[chromosome] != null) {
            var referenceSubStr = this.sequence[chromosome].substr((args.start - this.start[chromosome]), region.length());
            return referenceSubStr;
        } else {
            console.log("SequenceRender: this.sequence[chromosome] is undefined");
            return "";
        }
    }
};<|endoftext|>


<commit_before>var config = require('../../config/config'),
    request = require('request'),
    rp = require('request-promise');

module.exports = {

  getUserName: function getUserName(sender) {
    return rp({
      url: 'https://graph.facebook.com/v2.6/' + sender,
      qs: {
        access_token: config.page_access_token,
        fields: "first_name,last_name"
      },
      method: 'GET'
    })
    .then (function(data) {
      return JSON.parse(data);
    });
  },

  sendTextMessage: function sendTextMessage(sender, text) {
    messageData = {
      text:text
    };
    request({
      url: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {access_token:config.page_access_token},
      method: 'POST',
      json: {
        recipient: {id: sender},
        message: messageData
      }
    }, function(error, response, body) {
      if (error) {
        console.log('Error sending messages: ', error);
      } else if (response.body.error) {
        console.log('Error: ', response.body.error);
      }
    });
  },

  sendGenericMessage: function sendGenericMessage(sender) {
    messageData = {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "generic",
          "elements": [{
            "title": "Feeling down?",
            "subtitle": "Option #1",
            "image_url": "http://messengerdemo.parseapp.com/img/rift.png",
            "buttons": [{
              "type": "web_url",
              "url": "http://weavesilk.com/",
              "title": "Peaceful Website"
            }, {
              "type": "postback",
              "title": "Postback",
              "payload": "Payload for first element in a generic bubble",
            }],
          }]
        }
      }
    };
    request({
      url: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {access_token:config.page_access_token},
      method: 'POST',
      json: {
        recipient: {id:sender},
        message: messageData,
      }
    }, function(error, response, body) {
      if (error) {
        console.log('Error sending message: ', error);
      } else if (response.body.error) {
        console.log('Error: ', response.body.error);
      }
    });
  },

  sendQuickReply: function sendQuickReply(sender){
  messageData = {
    text: 'Please choose a department: ',
    quick_replies: [
      { content_type: 'text', title: 'HR', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_RED' },
      { content_type: 'text', title: 'IT', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' },
      { content_type: 'text', title: 'Marketing', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' },
      { content_type: 'text', title: 'Sales', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' },
      { content_type: 'text', title: 'Business', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' },
      { content_type: 'text', title: 'I don\'t know all the departments', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' }
    ]
  };
  request({
      url: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {access_token:config.page_access_token},
      method: 'POST',
      json: {
        recipient: {id:sender},
        message: messageData,
      }
    }, function(error, response, body) {
      if (error) {
        console.log('Error sending message: ', error);
      } else if (response.body.error) {
        console.log('Error: ', response.body.error);
      }
    });
  }
}

<commit_msg>Playing with quick reply responses<commit_after>var config = require('../../config/config'),
    request = require('request'),
    rp = require('request-promise');

module.exports = {

  getUserName: function getUserName(sender) {
    return rp({
      url: 'https://graph.facebook.com/v2.6/' + sender,
      qs: {
        access_token: config.page_access_token,
        fields: "first_name,last_name"
      },
      method: 'GET'
    })
    .then (function(data) {
      return JSON.parse(data);
    });
  },

  sendTextMessage: function sendTextMessage(sender, text) {
    messageData = {
      text:text
    };
    request({
      url: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {access_token:config.page_access_token},
      method: 'POST',
      json: {
        recipient: {id: sender},
        message: messageData
      }
    }, function(error, response, body) {
      if (error) {
        console.log('Error sending messages: ', error);
      } else if (response.body.error) {
        console.log('Error: ', response.body.error);
      }
    });
  },

  sendGenericMessage: function sendGenericMessage(sender) {
    messageData = {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "generic",
          "elements": [{
            "title": "Feeling down?",
            "subtitle": "Option #1",
            "image_url": "http://messengerdemo.parseapp.com/img/rift.png",
            "buttons": [{
              "type": "web_url",
              "url": "http://weavesilk.com/",
              "title": "Peaceful Website"
            }, {
              "type": "postback",
              "title": "Postback",
              "payload": "Payload for first element in a generic bubble",
            }],
          }]
        }
      }
    };
    request({
      url: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {access_token:config.page_access_token},
      method: 'POST',
      json: {
        recipient: {id:sender},
        message: messageData,
      }
    }, function(error, response, body) {
      if (error) {
        console.log('Error sending message: ', error);
      } else if (response.body.error) {
        console.log('Error: ', response.body.error);
      }
    });
  },

  sendQuickReply: function sendQuickReply(sender){
  messageData = {
    text: 'Please choose a department: ',
    quick_replies: [
      { content_type: 'text', title: 'HR', payload: fb.sendTextMessage(sender, "Hey look, you chose HR")},
      { content_type: 'text', title: 'IT', payload: fb.sendTextMessage(sender, "Hey look, you chose IT") },
      { content_type: 'text', title: 'Marketing', payload: fb.sendTextMessage(sender, "Hey look, you chose Marketing") },
      { content_type: 'text', title: 'Sales', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' },
      { content_type: 'text', title: 'Business', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' },
      { content_type: 'text', title: 'I don\'t know all the departments', payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN' }
    ]
  };
  request({
      url: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {access_token:config.page_access_token},
      method: 'POST',
      json: {
        recipient: {id:sender},
        message: messageData,
      }
    }, function(error, response, body) {
      if (error) {
        console.log('Error sending message: ', error);
      } else if (response.body.error) {
        console.log('Error: ', response.body.error);
      }
    });
  }
}

<|endoftext|>


<commit_before>'use strict'

global.SEGMENT_INTEL = 'room_intel'
sos.lib.vram.markCritical(SEGMENT_INTEL)

const recheckInterval = 10000
const maxScoutDistance = 11

// To reduce memory we use short keys for the room objects, so for readability those are mapped to global constants.
global.INTEL_LEVEL = 'l'
global.INTEL_PRACTICAL_LEVEL = 'r'
global.INTEL_OWNER = 'o'
global.INTEL_MINERAL = 'm'
global.INTEL_SOURCES = 's'
global.INTEL_UPDATED = 'u'
global.INTEL_RESOURCE_POSITIONS = 'p'

Room.prototype.saveIntel = function (refresh = false) {
  if (!Memory.intel) {
    Memory.intel = {
      buffer: {},
      targets: {},
      active: {}
    }
  }

  // Pull existing data in order to skip calculating things that never change
  let roominfo
  if (refresh) {
    roominfo = {}
  } else {
    roominfo = this.getIntel()
    if (!roominfo) {
      roominfo = {}
    }
  }

  roominfo[INTEL_UPDATED] = Game.time

  // Record room owner, level.
  if (this.controller) {
    if (this.controller.owner) {
      roominfo[INTEL_OWNER] = this.controller.owner.username
      roominfo[INTEL_PRACTICAL_LEVEL] = this.getPracticalRoomLevel()
    } else if (this.controller.reservation) {
      roominfo[INTEL_OWNER] = this.controller.reservation.username
    }
    if (this.controller.level) {
      roominfo[[INTEL_LEVEL]] = this.controller.level
    }
  }

  // Record static resources - minerals, number of sources, and their locations in SK rooms (for pathfinding)
  const recordResourceLocation = this.structures[STRUCTURE_KEEPER_LAIR] !== undefined

  if (recordResourceLocation) {
    roominfo[INTEL_RESOURCE_POSITIONS] = []
  }
  if (!roominfo[INTEL_MINERAL]) {
    const minerals = this.find(FIND_MINERALS)
    if (minerals.length > 0) {
      roominfo[INTEL_MINERAL] = minerals[0].mineralType
      if (recordResourceLocation) {
        roominfo[INTEL_RESOURCE_POSITIONS].push(minerals[0].pos.serialize())
      }
    }
  }
  if (!roominfo[INTEL_SOURCES]) {
    const sources = this.find(FIND_SOURCES)
    if (sources.length > 0) {
      roominfo[INTEL_SOURCES] = sources.length
      if (recordResourceLocation) {
        let source
        for (source of sources) {
          roominfo[INTEL_RESOURCE_POSITIONS].push(source.pos.serialize())
        }
      }
    }
  }

  // Record any portal destinations, distinguishing between inter and intra shard.
  /*
  if (this.structures[STRUCTURE_PORTAL] && this.structures[STRUCTURE_PORTAL].length > 0) {
    const portals = this.structures[STRUCTURE_PORTAL]
    let portal
    for (portal of portals) {

    }
  }
  */

  // Remove this room as a scouting target and active assignments
  if (Memory.intel.targets[this.name]) {
    delete Memory.intel.targets[this.name]
  }
  if (Memory.intel.active[this.name]) {
    delete Memory.intel.active[this.name]
  }

  Memory.intel.buffer[this.name] = roominfo
  return roominfo
}

Room.flushIntelToSegment = function () {
  if (!Memory.intel || !Memory.intel.buffer) {
    return
  }
  const rooms = Object.keys(Memory.intel.buffer)
  if (rooms.length <= 0) {
    return
  }
  const intelmap = sos.lib.vram.getData(SEGMENT_INTEL)
  sos.lib.vram.markDirty(SEGMENT_INTEL)
  let roomname
  for (roomname in Memory.intel.buffer) {
    intelmap[roomname] = Memory.intel.buffer[roomname]
    delete Memory.intel.buffer[roomname]
  }
}

Room.getIntel = function (roomname) {
  if (Memory.intel && Memory.intel.buffer[roomname]) {
    return Memory.intel.buffer[roomname]
  }

  const intelmap = sos.lib.vram.getData(SEGMENT_INTEL)
  if (intelmap[roomname]) {
    if (Game.time - intelmap[roomname][INTEL_UPDATED] > recheckInterval) {
      Room.requestIntel(roomname)
    }
    return intelmap[roomname]
  }

  if (Game.rooms[roomname]) {
    Game.rooms[roomname].saveIntel(true)
    if (Memory.intel && Memory.intel.buffer[roomname]) {
      return Memory.intel.buffer[roomname]
    }
  } else {
    Room.requestIntel(roomname)
  }

  return false
}

Room.prototype.getIntel = function () {
  return Room.getIntel(this.name)
}

Room.getResourcesPositions = function (roomname) {
  const roominfo = Room.getIntel(roomname)
  if (!roominfo[INTEL_RESOURCE_POSITIONS]) {
    return false
  }
  let positions = []
  let serializedPosition
  for (serializedPosition of roominfo[INTEL_RESOURCE_POSITIONS]) {
    positions.push(RoomPosition.deserialize(serializedPosition))
  }
  return positions
}

Room.requestIntel = function (roomname) {
  if (!Memory.intel) {
    Memory.intel = {
      buffer: {},
      targets: {},
      active: {}
    }
  }
  if (!Memory.intel.targets[roomname]) {
    Memory.intel.targets[roomname] = Game.time
  }
}

Room.getScoutTarget = function (creep) {
  let target = false
  const targetRooms = !Memory.intel ? [] : _.shuffle(Object.keys(Memory.intel.targets))
  const assignedRooms = !Memory.intel ? [] : Object.keys(Memory.intel.active)

  if (targetRooms.length > 0) {
    let oldest = false
    let testRoom
    for (testRoom of targetRooms) {
      // Filter out rooms that already have a scount creep assigned to them.
      if (assignedRooms.includes(testRoom)) {
        if (Game.creeps[Memory.intel.active[testRoom]]) {
          continue
        } else {
          delete Memory.intel.active[testRoom]
        }
      }
      if (Game.map.getRoomLinearDistance(creep.room.name, testRoom) > maxScoutDistance) {
        continue
      }
      if (!oldest || oldest > Memory.intel.targets[creep.room.name]) {
        oldest = Memory.intel.targets[creep.room.name]
        target = creep.room.name
      }
    }
  }

  if (Game.rooms[target]) {
    target = false
  }

  if (!target) {
    const adjacent = _.shuffle(Object.values(Game.map.describeExits(creep.room.name)))
    let oldest = 0
    let testRoom
    for (testRoom of adjacent) {
      const roominfo = Room.getIntel(testRoom)
      let age
      if (!roominfo) {
        age = Infinity
      } else {
        age = assignedRooms.includes(testRoom) ? 0 : Game.time - roominfo[INTEL_UPDATED]
      }
      if (target && oldest === age) {
        let curDistance = Game.map.getRoomLinearDistance(creep.room.name, target)
        let testDistance = Game.map.getRoomLinearDistance(creep.room.name, testRoom)
        if (curDistance > testDistance) {
          target = testRoom
        }
      } else if (oldest < age) {
        oldest = age
        target = testRoom
      }
    }
  }

  creep.memory.starget = target
  Memory.intel.active[target] = creep.name
  return target
}
<commit_msg>Fix compatibility with main server<commit_after>'use strict'

global.SEGMENT_INTEL = 'room_intel'
sos.lib.vram.markCritical(SEGMENT_INTEL)

const recheckInterval = 10000
const maxScoutDistance = 11

// To reduce memory we use short keys for the room objects, so for readability those are mapped to global constants.
global.INTEL_LEVEL = 'l'
global.INTEL_PRACTICAL_LEVEL = 'r'
global.INTEL_OWNER = 'o'
global.INTEL_MINERAL = 'm'
global.INTEL_SOURCES = 's'
global.INTEL_UPDATED = 'u'
global.INTEL_RESOURCE_POSITIONS = 'p'

Room.prototype.saveIntel = function (refresh = false) {
  if (!Memory.intel) {
    Memory.intel = {
      buffer: {},
      targets: {},
      active: {}
    }
  }

  // Pull existing data in order to skip calculating things that never change
  let roominfo
  if (refresh) {
    roominfo = {}
  } else {
    roominfo = this.getIntel()
    if (!roominfo) {
      roominfo = {}
    }
  }

  roominfo[INTEL_UPDATED] = Game.time

  // Record room owner, level.
  if (this.controller) {
    if (this.controller.owner) {
      roominfo[INTEL_OWNER] = this.controller.owner.username
      roominfo[INTEL_PRACTICAL_LEVEL] = this.getPracticalRoomLevel()
    } else if (this.controller.reservation) {
      roominfo[INTEL_OWNER] = this.controller.reservation.username
    }
    if (this.controller.level) {
      roominfo[[INTEL_LEVEL]] = this.controller.level
    }
  }

  // Record static resources - minerals, number of sources, and their locations in SK rooms (for pathfinding)
  const recordResourceLocation = this.structures[STRUCTURE_KEEPER_LAIR] !== undefined

  if (recordResourceLocation) {
    roominfo[INTEL_RESOURCE_POSITIONS] = []
  }
  if (!roominfo[INTEL_MINERAL]) {
    const minerals = this.find(FIND_MINERALS)
    if (minerals.length > 0) {
      roominfo[INTEL_MINERAL] = minerals[0].mineralType
      if (recordResourceLocation) {
        roominfo[INTEL_RESOURCE_POSITIONS].push(minerals[0].pos.serialize())
      }
    }
  }
  if (!roominfo[INTEL_SOURCES]) {
    const sources = this.find(FIND_SOURCES)
    if (sources.length > 0) {
      roominfo[INTEL_SOURCES] = sources.length
      if (recordResourceLocation) {
        let source
        for (source of sources) {
          roominfo[INTEL_RESOURCE_POSITIONS].push(source.pos.serialize())
        }
      }
    }
  }

  // Record any portal destinations, distinguishing between inter and intra shard.
  /*
  if (this.structures[STRUCTURE_PORTAL] && this.structures[STRUCTURE_PORTAL].length > 0) {
    const portals = this.structures[STRUCTURE_PORTAL]
    let portal
    for (portal of portals) {

    }
  }
  */

  // Remove this room as a scouting target and active assignments
  if (Memory.intel.targets[this.name]) {
    delete Memory.intel.targets[this.name]
  }
  if (Memory.intel.active[this.name]) {
    delete Memory.intel.active[this.name]
  }

  Memory.intel.buffer[this.name] = roominfo
  return roominfo
}

Room.flushIntelToSegment = function () {
  if (!Memory.intel || !Memory.intel.buffer) {
    return
  }
  const rooms = Object.keys(Memory.intel.buffer)
  if (rooms.length <= 0) {
    return
  }
  const intelmap = sos.lib.vram.getData(SEGMENT_INTEL)
  sos.lib.vram.markDirty(SEGMENT_INTEL)
  let roomname
  for (roomname in Memory.intel.buffer) {
    intelmap[roomname] = Memory.intel.buffer[roomname]
    delete Memory.intel.buffer[roomname]
  }
}

Room.getIntel = function (roomname) {
  if (Memory.intel && Memory.intel.buffer[roomname]) {
    return Memory.intel.buffer[roomname]
  }

  const intelmap = sos.lib.vram.getData(SEGMENT_INTEL)
  if (intelmap[roomname]) {
    if (Game.time - intelmap[roomname][INTEL_UPDATED] > recheckInterval) {
      Room.requestIntel(roomname)
    }
    return intelmap[roomname]
  }

  if (Game.rooms[roomname]) {
    Game.rooms[roomname].saveIntel(true)
    if (Memory.intel && Memory.intel.buffer[roomname]) {
      return Memory.intel.buffer[roomname]
    }
  } else {
    Room.requestIntel(roomname)
  }

  return false
}

Room.prototype.getIntel = function () {
  return Room.getIntel(this.name)
}

Room.getResourcesPositions = function (roomname) {
  const roominfo = Room.getIntel(roomname)
  if (!roominfo[INTEL_RESOURCE_POSITIONS]) {
    return false
  }
  let positions = []
  let serializedPosition
  for (serializedPosition of roominfo[INTEL_RESOURCE_POSITIONS]) {
    positions.push(RoomPosition.deserialize(serializedPosition))
  }
  return positions
}

Room.requestIntel = function (roomname) {
  if (!Memory.intel) {
    Memory.intel = {
      buffer: {},
      targets: {},
      active: {}
    }
  }
  if (!Memory.intel.targets[roomname]) {
    Memory.intel.targets[roomname] = Game.time
  }
}

Room.getScoutTarget = function (creep) {
  let target = false
  const targetRooms = !Memory.intel ? [] : _.shuffle(Object.keys(Memory.intel.targets))
  const assignedRooms = !Memory.intel ? [] : Object.keys(Memory.intel.active)

  if (targetRooms.length > 0) {
    let oldest = false
    let testRoom
    for (testRoom of targetRooms) {
      // Filter out rooms that already have a scount creep assigned to them.
      if (assignedRooms.includes(testRoom)) {
        if (Game.creeps[Memory.intel.active[testRoom]]) {
          continue
        } else {
          delete Memory.intel.active[testRoom]
        }
      }
      if (Game.map.getRoomLinearDistance(creep.room.name, testRoom) > maxScoutDistance) {
        continue
      }
      if (!oldest || oldest > Memory.intel.targets[creep.room.name]) {
        oldest = Memory.intel.targets[creep.room.name]
        target = creep.room.name
      }
    }
  }

  if (Game.rooms[target]) {
    target = false
  }

  if (!target) {
    const adjacent = _.shuffle(_.values(Game.map.describeExits(creep.room.name)))
    let oldest = 0
    let testRoom
    for (testRoom of adjacent) {
      const roominfo = Room.getIntel(testRoom)
      let age
      if (!roominfo) {
        age = Infinity
      } else {
        age = assignedRooms.indexOf(testRoom) >= 0 ? 0 : Game.time - roominfo[INTEL_UPDATED]
      }
      if (target && oldest === age) {
        let curDistance = Game.map.getRoomLinearDistance(creep.room.name, target)
        let testDistance = Game.map.getRoomLinearDistance(creep.room.name, testRoom)
        if (curDistance > testDistance) {
          target = testRoom
        }
      } else if (oldest < age) {
        oldest = age
        target = testRoom
      }
    }
  }

  creep.memory.starget = target
  Memory.intel.active[target] = creep.name
  return target
}
<|endoftext|>


<commit_before>const pending = {}

export default function (time, continueChain, options = {}) {
  const id = Symbol('id')
  const {
    terminateChain = [],
    immediate = true,
    throttle = true,
  } = options

  const timeout = function debounceTimeout () {
    if (pending[id].continue) {
      // continue the final signal
      pending[id].continue()
      // immediate debounce should wait until time before sending immediate again
      if (immediate) {
        pending[id] = {
          timeout: setTimeout(timeout, time)
        }
      } else {
        delete pending[id]
      }
    } else {
      // no pending signals
      delete pending[id]
    }
  }

  const debounce = function debounce ({ output }) {
    if (pending[id]) {
      // not first time
      if (pending[id].terminate) {
        // terminate the previous signal
        pending[id].terminate()

        // convert from throttle to a debounce
        // todo: this flag should eventually be removed
        if (!throttle) {
          clearTimeout(pending[id].timeout)
          pending[id] = {
            timeout: setTimeout(timeout, time)
          }
        }
      }
      // replace previous signal with this one
      pending[id].continue = output.continue
      pending[id].terminate = output.terminate
    } else {
      // first time
      pending[id] = {
        timeout: setTimeout(timeout, time)
      }
      if (!immediate) {
        // queue the signal
        pending[id].continue = output.continue
        pending[id].terminate = output.terminate
      } else {
        // continue the signal
        output.continue()
      }
    }
  }

  debounce.outputs = [
    'continue',
    'terminate'
  ]

  debounce.displayName = `addons.debounce(${time}, ...)`

  return [
    debounce, {
      continue: continueChain,
      terminate: terminateChain
    }
  ]
}
<commit_msg>Show deprecation warning for upcoming changes to debounce behaviour<commit_after>const pending = {}

export default function (time, continueChain, options = null) {
  const id = Symbol('id')

  if (options === null) {
    console.warn('cerebral-addons: calling debounce() without options has been temporarily deprecated. https://gist.github.com/garth/c1ff94b9cb41ad1b107d')
  }

  const {
    terminateChain = [],
    immediate = true,
    throttle = true,
  } = (options || {})

  const timeout = function debounceTimeout () {
    if (pending[id].continue) {
      // continue the final signal
      pending[id].continue()
      // immediate debounce should wait until time before sending immediate again
      if (immediate) {
        pending[id] = {
          timeout: setTimeout(timeout, time)
        }
      } else {
        delete pending[id]
      }
    } else {
      // no pending signals
      delete pending[id]
    }
  }

  const debounce = function debounce ({ output }) {
    if (pending[id]) {
      // not first time
      if (pending[id].terminate) {
        // terminate the previous signal
        pending[id].terminate()

        // convert from throttle to a debounce
        // todo: this flag should eventually be removed
        if (!throttle) {
          clearTimeout(pending[id].timeout)
          pending[id] = {
            timeout: setTimeout(timeout, time)
          }
        }
      }
      // replace previous signal with this one
      pending[id].continue = output.continue
      pending[id].terminate = output.terminate
    } else {
      // first time
      pending[id] = {
        timeout: setTimeout(timeout, time)
      }
      if (!immediate) {
        // queue the signal
        pending[id].continue = output.continue
        pending[id].terminate = output.terminate
      } else {
        // continue the signal
        output.continue()
      }
    }
  }

  debounce.outputs = [
    'continue',
    'terminate'
  ]

  debounce.displayName = `addons.debounce(${time}, ...)`

  return [
    debounce, {
      continue: continueChain,
      terminate: terminateChain
    }
  ]
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.fs',
  name: 'File',

  documentation: 'Represents a file',

  properties: [
    {
      class: 'String',
      name: 'id',
      documentation: 'GUID'
    },
    {
      class: 'String',
      name: 'filename',
      documentation: 'Filename'
    },
    {
      class: 'Long',
      name: 'filesize',
      documentation: 'Filesize'
    },
    {
      class: 'String',
      name: 'mimeType',
      documentation: 'File mime type'
    },
    {
      class: 'Blob',
      name: 'data',
      documentation: 'File data'
    },
    {
      class: 'String',
      name: 'address',
      transient: true,
      expression: function (id) {
        var sessionId = localStorage['defaultSession'];
        var url = window.location.origin + '/service/httpFileService/' + id
        // attach session id if available
        if ( sessionId ) {
          url += '?sessionId=' + sessionId;
        }
        return url;
      }
    }
  ]
});
<commit_msg>export file data as csv<commit_after>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.fs',
  name: 'File',

  documentation: 'Represents a file',

  properties: [
    {
      class: 'String',
      name: 'id',
      documentation: 'GUID'
    },
    {
      class: 'String',
      name: 'filename',
      documentation: 'Filename'
    },
    {
      class: 'Long',
      name: 'filesize',
      documentation: 'Filesize'
    },
    {
      class: 'String',
      name: 'mimeType',
      documentation: 'File mime type'
    },
    {
      class: 'Blob',
      name: 'data',
      documentation: 'File data',
      adapt: function(oldObj, newObj) {
        return newObj;
      }
    },
    {
      class: 'String',
      name: 'address',
      transient: true,
      expression: function (id) {
        var sessionId = localStorage['defaultSession'];
        var url = window.location.origin + '/service/httpFileService/' + id
        // attach session id if available
        if ( sessionId ) {
          url += '?sessionId=' + sessionId;
        }
        return url;
      }
    }
  ]
});
<|endoftext|>


<commit_before>import _ from "lodash/core";
import capitalize from "lodash/capitalize";
import repeat from "lodash/repeat";

export default {
  // Returns the char at the position of the given utf8 string.
  // If position is greater than string length, then it returns nil.
  // at(t, integer) :: string | null
  at(str, position) {
    const isNegative = Math.sign(position) === -1;

    if (position >= str.length) {
      return null;
    }
    else if (isNegative) {
      return str.charAt(str.length - Math.abs(position)) || null;
    }
    return str.charAt(position);
  },

  // Converts the first character in the given string to
  // uppercase and the remainder to lowercase.
  // capitalize(string) :: string
  capitalize,

  // Checks if string contains any of the given contents.
  // contents can be either a single string or a list of strings.
  // contains(string, [string] | string) :: boolean
  contains(str, pat) {
    let patterns;
    if (_.isArray(pat)) {
      patterns = pat;
    }
    else {
      patterns = [pat];
    }

    const results = patterns.map(pattern => {
      const result = str.match(pattern);
      return result !== null;
    });

    return results.indexOf(true) >= 0;
  },

  // Converts all characters in the given string to lowercase.
  // downcase(string) :: string
  downcase(str) {
    return str.toLowerCase();
  },

  // Returns a string subject duplicated n times.
  // duplicate(string, non_neg_integer) :: string
  duplicate: repeat,
};
<commit_msg>Implement flow for string module<commit_after>// @flow
import _ from "lodash/core";
import capitalize from "lodash/capitalize";
import repeat from "lodash/repeat";

export default {
  // Returns the char at the position of the given utf8 string.
  // If position is greater than string length, then it returns nil.
  // at(t, integer) :: string | null
  at(str: string, position: number): ?string {
    const isNegative = Math.sign(position) === -1;

    if (position >= str.length) {
      return null;
    }
    else if (isNegative) {
      return str.charAt(str.length - Math.abs(position)) || null;
    }
    return str.charAt(position);
  },

  // Converts the first character in the given string to
  // uppercase and the remainder to lowercase.
  // capitalize(string) :: string
  capitalize,

  // Checks if string contains any of the given contents.
  // contents can be either a single string or a list of strings.
  // contains(string, [string] | string) :: boolean
  contains(str: string, patterns: Array<string> | string): boolean {
    if (_.isString(patterns)) {
      return do_contains(str, [patterns]);
    } else {
      return do_contains(str, patterns);
    }
  },

  // Converts all characters in the given string to lowercase.
  // downcase(string) :: string
  downcase(str: string): string {
    return str.toLowerCase();
  },

  // Returns a string subject duplicated n times.
  // duplicate(string, non_neg_integer) :: string
  duplicate: repeat,
};

function do_contains(str: string, patterns: Array<string>): boolean {
  const results = patterns.map(pattern => {
    const result = str.match(pattern);
    return result !== null;
  });

  return results.indexOf(true) >= 0;
}
<|endoftext|>


<commit_before>var Vue = require('vue');
var insertCss = require('insert-css');
var bind = require('component-bind');
var escape = require('escape-html');
var is = require('is');
var dom = require('vue/src/util/dom');

var MESSAGES = require('nps-translations');

insertCss(require('./index.scss'));

var RATING_STATE = 'rating';
var FEEDBACK_STATE = 'feedback';
var THANKS_STATE = 'thanks';
var FILLED_STATE = 'filled';

var DIALOG_SKIN = 'dialog';
var PANEL_SKIN = 'panel';
var BAR_SKIN = 'bar';

var Survey = Vue.extend({
  template: require('./survey.html'),
  partials: {
    rating: require('./rating.html'),
    feedback: require('./feedback.html'),
    scale: require('./scale.html'),
    thanks: require('./thanks.html'),
    filled: require('./filled.html'),
    'powered-by': require('./powered-by.html'),
    panel: require('./panel.html'),
    dialog: require('./dialog.html'),
    bar: require('./bar.html')
  },
  replace: true,
  data: function() {
    return {
      // model
      rating: null,
      feedback: '',
      reason: '',

      // state
      visible: false,
      state: RATING_STATE,
      translation: null,

      // settings
      language: 'en',
      serviceName: null,
      poweredBy: true,
      skin: DIALOG_SKIN,
      theme: 'pink',
      preview: false, // preview mode - positioned inside a preview div
      position: 'cr', // tl (top-right), tr, bl, br
      test: false
    };
  },
  ready: function() {
    if (this.showFeedbackText) {
      this.setTimeout(this.focusFeedback, 600);
    }
  },
  computed: {
    showCloseIcon: function() {
      return this.state === FEEDBACK_STATE || this.state === RATING_STATE;
    },
    showFeedbackText: function() {
      return this.state === FEEDBACK_STATE;
    },
    ratings: function() {
      var selectedRating = this.rating;
      return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(function(rating) {
        return {
          rating: rating,
          selected: selectedRating !== null && rating <= selectedRating
        };
      });
    },
    likelyHtml: function() {
      var serviceName = is.string(this.serviceName) ? this.serviceName.trim() : null;
      var us = this.t('US');
      var serviceHtml = serviceName ? '' + escape(serviceName) + '' : us;
      return escape(this.t('HOW_LIKELY')).replace('%s', serviceHtml);
    },
    hasReasons: function() {
      var reasons = this.t('REASONS');
      return reasons && reasons.length > 0;
    },
    vertical: function() {
      switch (this.position[0]) {
        case 'b':
          return 'bottom';
        case 't':
          return 'top';
        default:
          return 'middle';
      }
    },
    horizontal: function() {
      switch (this.position[1]) {
        case 'l':
          return 'left';
        case 'r':
          return 'right';
        default:
          return 'center';
      }
    },
    previewClass: function() {
      if (this.preview) {
        return 'nps-preview';
      }
      return '';
    },
    category: function() {
      if (!is.number(this.rating)) {
        return null;
      }
      if (this.rating <= 6) {
        return 'detractor';
      }
      if (this.rating <= 8) {
        return 'passive';
      }
      return 'promoter'
    }
  },
  methods: {
    inState: function() {
      var states = Array.prototype.slice.call(arguments);
      return states.indexOf(this.state) !== -1;
    },
    nextTick: function(fn) {
      Vue.nextTick(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }));
    },
    setTimeout: function(fn, timeout) {
      setTimeout(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }), timeout);
    },
    _t: function(key, param) {
      if (this.translation) {
        if (this.translation[key]) {
          return this.translation[key];
        }
        if (key === 'FOLLOWUP' && this.translation['IMPROVE']) {
          return this.translation['IMPROVE'];
        }
      }
      var shortLanguage = is.string(this.language) ? this.language.split('_')[0] : '';
      var messages = MESSAGES[this.language] || MESSAGES[shortLanguage] || MESSAGES.en;
      return messages[key];
    },
    t: function(key, param) {
      if (this.category) {
        var value = this._t(key + '_' + this.category.toUpperCase());
        if (value) {
          return value;
        }
      }
      return this._t(key, value);
    },
    selectRating: function (rating) {
      this.rating = rating;
      this.state = FEEDBACK_STATE;
      this.setTimeout(this.focusFeedback, 500);
      this.$emit('ratingSelect');
    },
    focusFeedback: function() {
      this.nextTick(function () {
        var $feedback = this.$el.querySelector('input') || this.$el.querySelector('textarea');
        if ($feedback) {
          this.nextTick(function() {
            $feedback.focus();
          });
        }
      });
    },
    show: function() {
      this.visible = true;
    },
    hide: function() {
      this.visible = false;
    },
    submit: function() {
      this.$emit('submit');
      this.state = THANKS_STATE;
      if (this.skin === DIALOG_SKIN || this.skin === BAR_SKIN) {
        this.setTimeout(function() {
          this.hide();
        }, 800);
      }
    },
    onClose: function() {
      this.hide();
      this.$emit('dismiss');
    }
  },
  transitions: {
    next: {
      leave: function(el, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        this.leave = el;
        this.setTimeout(function() {
          done();
          delete this.leave;
        }, 600);
      },
      enter: function(enter, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        var content = enter.parentNode;
        var bounding = content.parentNode;
        var leave = this.leave;

        bounding.style.height = getComputedStyle(leave || enter).height;
        content.style.top = 0;
        if (leave) {
          leave.style.opacity = 1;
        }

        this.setTimeout(function() {
          dom.addClass(bounding, 'nps-next');
          this.setTimeout(function() {
            content.style.top = '-' + bounding.style.height;
            bounding.style.height = getComputedStyle(enter).height;
            if (leave) {
              leave.style.opacity = 0;
            }

            this.setTimeout(function() {
              dom.removeClass(bounding, 'nps-next');
              content.style.top = '';
              if (leave) {
                leave.style.display = 'none';
              }
              bounding.style.height = '';
              done();
            }, 500);
          }, 0);
        }, 0);
      }
    }
  }
});

module.exports = Survey;
<commit_msg>make use of is.number<commit_after>var Vue = require('vue');
var insertCss = require('insert-css');
var bind = require('component-bind');
var escape = require('escape-html');
var is = require('is');
var dom = require('vue/src/util/dom');

var MESSAGES = require('nps-translations');

insertCss(require('./index.scss'));

var RATING_STATE = 'rating';
var FEEDBACK_STATE = 'feedback';
var THANKS_STATE = 'thanks';
var FILLED_STATE = 'filled';

var DIALOG_SKIN = 'dialog';
var PANEL_SKIN = 'panel';
var BAR_SKIN = 'bar';

var Survey = Vue.extend({
  template: require('./survey.html'),
  partials: {
    rating: require('./rating.html'),
    feedback: require('./feedback.html'),
    scale: require('./scale.html'),
    thanks: require('./thanks.html'),
    filled: require('./filled.html'),
    'powered-by': require('./powered-by.html'),
    panel: require('./panel.html'),
    dialog: require('./dialog.html'),
    bar: require('./bar.html')
  },
  replace: true,
  data: function() {
    return {
      // model
      rating: null,
      feedback: '',
      reason: '',

      // state
      visible: false,
      state: RATING_STATE,
      translation: null,

      // settings
      language: 'en',
      serviceName: null,
      poweredBy: true,
      skin: DIALOG_SKIN,
      theme: 'pink',
      preview: false, // preview mode - positioned inside a preview div
      position: 'cr', // tl (top-right), tr, bl, br
      test: false
    };
  },
  ready: function() {
    if (this.showFeedbackText) {
      this.setTimeout(this.focusFeedback, 600);
    }
  },
  computed: {
    showCloseIcon: function() {
      return this.state === FEEDBACK_STATE || this.state === RATING_STATE;
    },
    showFeedbackText: function() {
      return this.state === FEEDBACK_STATE;
    },
    ratings: function() {
      var selectedRating = this.rating;
      return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(function(rating) {
        return {
          rating: rating,
          selected: is.number(selectedRating) && rating <= selectedRating
        };
      });
    },
    likelyHtml: function() {
      var serviceName = is.string(this.serviceName) ? this.serviceName.trim() : null;
      var us = this.t('US');
      var serviceHtml = serviceName ? '' + escape(serviceName) + '' : us;
      return escape(this.t('HOW_LIKELY')).replace('%s', serviceHtml);
    },
    hasReasons: function() {
      var reasons = this.t('REASONS');
      return reasons && reasons.length > 0;
    },
    vertical: function() {
      switch (this.position[0]) {
        case 'b':
          return 'bottom';
        case 't':
          return 'top';
        default:
          return 'middle';
      }
    },
    horizontal: function() {
      switch (this.position[1]) {
        case 'l':
          return 'left';
        case 'r':
          return 'right';
        default:
          return 'center';
      }
    },
    previewClass: function() {
      if (this.preview) {
        return 'nps-preview';
      }
      return '';
    },
    category: function() {
      if (!is.number(this.rating)) {
        return null;
      }
      if (this.rating <= 6) {
        return 'detractor';
      }
      if (this.rating <= 8) {
        return 'passive';
      }
      return 'promoter'
    }
  },
  methods: {
    inState: function() {
      var states = Array.prototype.slice.call(arguments);
      return states.indexOf(this.state) !== -1;
    },
    nextTick: function(fn) {
      Vue.nextTick(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }));
    },
    setTimeout: function(fn, timeout) {
      setTimeout(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }), timeout);
    },
    _t: function(key, param) {
      if (this.translation) {
        if (this.translation[key]) {
          return this.translation[key];
        }
        if (key === 'FOLLOWUP' && this.translation['IMPROVE']) {
          return this.translation['IMPROVE'];
        }
      }
      var shortLanguage = is.string(this.language) ? this.language.split('_')[0] : '';
      var messages = MESSAGES[this.language] || MESSAGES[shortLanguage] || MESSAGES.en;
      return messages[key];
    },
    t: function(key, param) {
      if (this.category) {
        var value = this._t(key + '_' + this.category.toUpperCase());
        if (value) {
          return value;
        }
      }
      return this._t(key, value);
    },
    selectRating: function (rating) {
      this.rating = rating;
      this.state = FEEDBACK_STATE;
      this.setTimeout(this.focusFeedback, 500);
      this.$emit('ratingSelect');
    },
    focusFeedback: function() {
      this.nextTick(function () {
        var $feedback = this.$el.querySelector('input') || this.$el.querySelector('textarea');
        if ($feedback) {
          this.nextTick(function() {
            $feedback.focus();
          });
        }
      });
    },
    show: function() {
      this.visible = true;
    },
    hide: function() {
      this.visible = false;
    },
    submit: function() {
      this.$emit('submit');
      this.state = THANKS_STATE;
      if (this.skin === DIALOG_SKIN || this.skin === BAR_SKIN) {
        this.setTimeout(function() {
          this.hide();
        }, 800);
      }
    },
    onClose: function() {
      this.hide();
      this.$emit('dismiss');
    }
  },
  transitions: {
    next: {
      leave: function(el, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        this.leave = el;
        this.setTimeout(function() {
          done();
          delete this.leave;
        }, 600);
      },
      enter: function(enter, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        var content = enter.parentNode;
        var bounding = content.parentNode;
        var leave = this.leave;

        bounding.style.height = getComputedStyle(leave || enter).height;
        content.style.top = 0;
        if (leave) {
          leave.style.opacity = 1;
        }

        this.setTimeout(function() {
          dom.addClass(bounding, 'nps-next');
          this.setTimeout(function() {
            content.style.top = '-' + bounding.style.height;
            bounding.style.height = getComputedStyle(enter).height;
            if (leave) {
              leave.style.opacity = 0;
            }

            this.setTimeout(function() {
              dom.removeClass(bounding, 'nps-next');
              content.style.top = '';
              if (leave) {
                leave.style.display = 'none';
              }
              bounding.style.height = '';
              done();
            }, 500);
          }, 0);
        }, 0);
      }
    }
  }
});

module.exports = Survey;
<|endoftext|>


<commit_before>import React from 'react';

import SearchContextCard, {
  SearchContextCardBase,
} from 'amo/components/SearchContextCard';
import { searchStart } from 'core/actions/search';
import {
  dispatchClientMetadata,
  dispatchSearchResults,
  fakeAddon,
} from 'tests/unit/amo/helpers';
import { getFakeI18nInst, shallowUntilTarget } from 'tests/unit/helpers';
import {
  ADDON_TYPE_EXTENSION,
  ADDON_TYPE_DICT,
  ADDON_TYPE_LANG,
  ADDON_TYPE_THEME,
} from 'core/constants';

describe('SearchContextCard', () => {
  let _store;

  function render(customProps = {}) {
    const props = {
      store: _store,
      ...customProps,
    };

    return shallowUntilTarget(
      <SearchContextCard
        i18n={getFakeI18nInst()}
        {...props}
      />,
      SearchContextCardBase
    );
  }

  function _searchStart(props = {}) {
    _store.dispatch(searchStart({ errorHandlerId: 'Search', ...props }));
  }

  beforeEach(() => {
    _store = dispatchClientMetadata().store;
  });

  it('should render a card', () => {
    const root = render();

    expect(root).toHaveClassName('SearchContextCard');
  });

  it('should render "searching" while loading without query', () => {
    _searchStart({ filters: {} });
    const root = render();

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('Loading add-ons');
  });

  it('should render during a search that is loading', () => {
    _searchStart({ filters: { query: 'test' } });
    const root = render();

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('Searching for "test"');
  });

  it('should render search results', () => {
    const { store } = dispatchSearchResults();
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 results for "test"');
  });

  it('should render results that lack a query', () => {
    const { store } = dispatchSearchResults({ filters: {} });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 add-ons found');
  });

  it('should use singular form when only one result is found', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
    });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 result for "test"');
  });

  it('should use singular form without query when only one result', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {},
    });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 add-on found');
  });

  it('should render empty results', () => {
    const { store } = dispatchSearchResults({ addons: [], filters: {} });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('No add-ons found');
  });

  // addonType = ADDON_TYPE_THEME
  it('should render singular form when only one result is found with addonType as ADDON_TYPE_THEME', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_THEME,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 theme found for "test"');
  });

  it('should render plural form when multiple results are found with addonType as ADDON_TYPE_THEME', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_THEME,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 themes found for "test"');
  });

  // addonType = ADDON_TYPE_DICT
  it('should render singular form when only one result is found with addonType as ADDON_TYPE_DICT', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_DICT,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 dictionary found for "test"');
  });

  it('should render plural form when multipe results are found with addonType as ADDON_TYPE_DICT', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_DICT,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 dictionaries found for "test"');
  });

  // addonType = ADDON_TYPE_EXTENSION
  it('should render singular form when only one result is found with addonType = ADDON_TYPE_EXTENSION', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_EXTENSION,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 extension found for "test"');
  });

  it('should render plural form when multipe results are found with addonType as ADDON_TYPE_EXTENSION', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_EXTENSION,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 extensions found for "test"');
  });

  // addonType = ADDON_TYPE_EXTENSION
  it('should render singular form when only one result is found with addonType as ADDON_TYPE_LANG', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_LANG,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 language pack found for "test"');
  });

  it('should render plural form when multipe results are found with addonType as ADDON_TYPE_LANG', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_LANG,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 language packs found for "test"');
  });
});

<commit_msg>Fix typo<commit_after>import React from 'react';

import SearchContextCard, {
  SearchContextCardBase,
} from 'amo/components/SearchContextCard';
import { searchStart } from 'core/actions/search';
import {
  dispatchClientMetadata,
  dispatchSearchResults,
  fakeAddon,
} from 'tests/unit/amo/helpers';
import { getFakeI18nInst, shallowUntilTarget } from 'tests/unit/helpers';
import {
  ADDON_TYPE_EXTENSION,
  ADDON_TYPE_DICT,
  ADDON_TYPE_LANG,
  ADDON_TYPE_THEME,
} from 'core/constants';

describe('SearchContextCard', () => {
  let _store;

  function render(customProps = {}) {
    const props = {
      store: _store,
      ...customProps,
    };

    return shallowUntilTarget(
      <SearchContextCard
        i18n={getFakeI18nInst()}
        {...props}
      />,
      SearchContextCardBase
    );
  }

  function _searchStart(props = {}) {
    _store.dispatch(searchStart({ errorHandlerId: 'Search', ...props }));
  }

  beforeEach(() => {
    _store = dispatchClientMetadata().store;
  });

  it('should render a card', () => {
    const root = render();

    expect(root).toHaveClassName('SearchContextCard');
  });

  it('should render "searching" while loading without query', () => {
    _searchStart({ filters: {} });
    const root = render();

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('Loading add-ons');
  });

  it('should render during a search that is loading', () => {
    _searchStart({ filters: { query: 'test' } });
    const root = render();

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('Searching for "test"');
  });

  it('should render search results', () => {
    const { store } = dispatchSearchResults();
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 results for "test"');
  });

  it('should render results that lack a query', () => {
    const { store } = dispatchSearchResults({ filters: {} });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 add-ons found');
  });

  it('should use singular form when only one result is found', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
    });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 result for "test"');
  });

  it('should use singular form without query when only one result', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {},
    });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 add-on found');
  });

  it('should render empty results', () => {
    const { store } = dispatchSearchResults({ addons: [], filters: {} });
    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('No add-ons found');
  });

  it('should render singular form when only one result is found with addonType ADDON_TYPE_THEME', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_THEME,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 theme found for "test"');
  });

  it('should render plural form when multiple results are found with addonType ADDON_TYPE_THEME', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_THEME,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 themes found for "test"');
  });

  it('should render singular form when only one result is found with addonType ADDON_TYPE_DICT', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_DICT,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 dictionary found for "test"');
  });

  it('should render plural form when multiple results are found with addonType ADDON_TYPE_DICT', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_DICT,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 dictionaries found for "test"');
  });

  it('should render singular form when only one result is found with addonType ADDON_TYPE_EXTENSION', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_EXTENSION,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 extension found for "test"');
  });

  it('should render plural form when multiple results are found with addonType ADDON_TYPE_EXTENSION', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_EXTENSION,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 extensions found for "test"');
  });

  it('should render singular form when only one result is found with addonType ADDON_TYPE_LANG', () => {
    const { store } = dispatchSearchResults({
      addons: { [fakeAddon.slug]: fakeAddon },
      filters: {
        addonType: ADDON_TYPE_LANG,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('1 language pack found for "test"');
  });

  it('should render plural form when multiple results are found with addonType ADDON_TYPE_LANG', () => {
    const { store } = dispatchSearchResults({
      filters: {
        addonType: ADDON_TYPE_LANG,
        query: 'test',
      },
    });

    const root = render({ store });

    expect(root.find('.SearchContextCard-header'))
      .toIncludeText('2 language packs found for "test"');
  });
});

<|endoftext|>


<commit_before>/*global jQuery, window, document, console, google, MarkerClusterer */

var Codeweek = window.Codeweek || {};

(function ($, Codeweek) {

    'use strict';

    var i,
        map,
        markers = {},
        place,
        placeinfowindow = null;

    function createMap(events, lat, lng, zoomVal) {
        var markerData = JSON.parse(events),
            markerData_len = markerData.length,
            markerClusterOptions = {gridSize: 30, maxZoom: 10},
            map = new google.maps.Map(document.getElementById('events-map'), {
                scrollwheel: false,
                zoom: zoomVal,
                center: new google.maps.LatLng(lat, lng),
                mapTypeControl: false,
                panControl: false,
                zoomControl: true,
                zoomControlOptions: {
                    style: google.maps.ZoomControlStyle.LARGE,
                    position: google.maps.ControlPosition.RIGHT_BOTTOM
                },
                scaleControl: true,
                streetViewControl: false,
                streetViewControlOptions: {
                    position: google.maps.ControlPosition.RIGHT_BOTTOM
                }
            });
        placeinfowindow = new google.maps.InfoWindow({
            content: "loading..."
        });

        for (i = 0; i <= markerData_len; i = i + 1) {
            var markdata = markerData[i];
            if (markdata && typeof markdata === 'object') {

                var markTitle = markerData[i].fields.title,
                    map_position = markerData[i].fields.geoposition.split(","),
                    markLat = map_position[0],
                    markLng = map_position[1],
                    map_event_id = markerData[i].pk,
                    map_event_slug = markerData[i].fields.slug,
                    markUrl = "/view/" + map_event_id + "/" + map_event_slug;

                markers[map_event_id] = createMarker(markTitle, markLat, markLng, markUrl);
            }
        }

        return new MarkerClusterer(map, markers, markerClusterOptions);
    }

    function createMarker(markTitle, markLat, markLng, markUrl) {
        var myLatLng = new google.maps.LatLng(parseFloat(markLat), parseFloat(markLng));
        var marker = new google.maps.Marker({
            position: myLatLng,
            map: map,
            title: markTitle,
            html: '
' + markTitle + '
'
        });
        google.maps.event.addListener(marker, 'click', function() {
                placeinfowindow.setContent(this.html);
                placeinfowindow.open(this.map, this);
         });

        return marker;
    }

    function setAutocomplete() {
        var input = /** @type {HTMLInputElement} */(
            document.getElementById('search-event'));
        var event_list_container = /** @type {HTMLInputElement} */(
            document.getElementById('events-list'));
        var autocomplete = new google.maps.places.Autocomplete(input);
        autocomplete.bindTo('bounds', map);
        var infowindow = new google.maps.InfoWindow();
        google.maps.event.addListener(autocomplete, 'place_changed', function () {
            infowindow.close();
            place = autocomplete.getPlace();
            if (!place.geometry) {
                return;
            }
            // If the place has a geometry, then present it on a map.
            if (place.geometry.viewport) {
                map.map.fitBounds(place.geometry.viewport);
            } else {
                map.map.setCenter(place.geometry.location);
                map.map.setZoom(17);  // Why 17? Because it looks good.
            }

            var country_code = 'CZ',
                country_name = '';
            if (place.address_components) {
                var address = place.address_components;
                for (var j = 0; j <= address.length; j++) {
                    if (address[j] && address[j].types[0] === 'country') {
                        country_code = address[j].short_name;
                        country_name = address[j].long_name;
                    }
                }

            }
            infowindow.open(map.map);
            infowindow.close();

            if ($.support.pjax) {
                $.pjax({url: '/' + country_code, container: event_list_container});
                $(document).on('pjax:success', function () {
                    $('#country').html(country_name);
                });

            }
        });
    }
    function zoomCountry(current_country) {
        var zoomgeocoder = new google.maps.Geocoder();
        zoomgeocoder.geocode({'address': current_country}, function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                var ne = results[0].geometry.viewport.getNorthEast();
                var sw = results[0].geometry.viewport.getSouthWest();
                map.map.fitBounds(results[0].geometry.viewport);
                map.map.setCenter(results[0].geometry.location);
            }
        });
    }

    function initialize(events, lon, lan) {
        map = createMap(events, lon, lan, 4);
        setAutocomplete();
        if (location.pathname !== "/") {
        var current_country = document.getElementById('country').innerHTML;
        zoomCountry(current_country);
        }
    }

    var search_events_handler = function () {
        var serch_query_input = $('#search-event'),
            search_event_btn = $('search-btn');

        search_event_btn.on('click', function (e) {
            e.preventDefault();
        });

    };

    var init = function (events, lon, lan) {

        $(function () {
            // Initialize map on front page
            google.maps.event.addDomListener(window, 'load', function () {
                initialize(events, lon, lan);
            });

            search_events_handler();

        });
    };

    Codeweek.Index = {};
    Codeweek.Index.init = init;

	$(".countryflag").click(function(sender){
		zoomCountry(sender.currentTarget.innerText);
		document.location.href = "#!" + sender.currentTarget.id;
	});

}(jQuery, Codeweek));

<commit_msg>Zoom (without reload) sets country name as well<commit_after>/*global jQuery, window, document, console, google, MarkerClusterer */

var Codeweek = window.Codeweek || {};

(function ($, Codeweek) {

    'use strict';

    var i,
        map,
        markers = {},
        place,
        placeinfowindow = null;

    function createMap(events, lat, lng, zoomVal) {
        var markerData = JSON.parse(events),
            markerData_len = markerData.length,
            markerClusterOptions = {gridSize: 30, maxZoom: 10},
            map = new google.maps.Map(document.getElementById('events-map'), {
                scrollwheel: false,
                zoom: zoomVal,
                center: new google.maps.LatLng(lat, lng),
                mapTypeControl: false,
                panControl: false,
                zoomControl: true,
                zoomControlOptions: {
                    style: google.maps.ZoomControlStyle.LARGE,
                    position: google.maps.ControlPosition.RIGHT_BOTTOM
                },
                scaleControl: true,
                streetViewControl: false,
                streetViewControlOptions: {
                    position: google.maps.ControlPosition.RIGHT_BOTTOM
                }
            });
        placeinfowindow = new google.maps.InfoWindow({
            content: "loading..."
        });

        for (i = 0; i <= markerData_len; i = i + 1) {
            var markdata = markerData[i];
            if (markdata && typeof markdata === 'object') {

                var markTitle = markerData[i].fields.title,
                    map_position = markerData[i].fields.geoposition.split(","),
                    markLat = map_position[0],
                    markLng = map_position[1],
                    map_event_id = markerData[i].pk,
                    map_event_slug = markerData[i].fields.slug,
                    markUrl = "/view/" + map_event_id + "/" + map_event_slug;

                markers[map_event_id] = createMarker(markTitle, markLat, markLng, markUrl);
            }
        }

        return new MarkerClusterer(map, markers, markerClusterOptions);
    }

    function createMarker(markTitle, markLat, markLng, markUrl) {
        var myLatLng = new google.maps.LatLng(parseFloat(markLat), parseFloat(markLng));
        var marker = new google.maps.Marker({
            position: myLatLng,
            map: map,
            title: markTitle,
            html: '
' + markTitle + '
'
        });
        google.maps.event.addListener(marker, 'click', function() {
                placeinfowindow.setContent(this.html);
                placeinfowindow.open(this.map, this);
         });

        return marker;
    }

    function setAutocomplete() {
        var input = /** @type {HTMLInputElement} */(
            document.getElementById('search-event'));
        var event_list_container = /** @type {HTMLInputElement} */(
            document.getElementById('events-list'));
        var autocomplete = new google.maps.places.Autocomplete(input);
        autocomplete.bindTo('bounds', map);
        var infowindow = new google.maps.InfoWindow();
        google.maps.event.addListener(autocomplete, 'place_changed', function () {
            infowindow.close();
            place = autocomplete.getPlace();
            if (!place.geometry) {
                return;
            }
            // If the place has a geometry, then present it on a map.
            if (place.geometry.viewport) {
                map.map.fitBounds(place.geometry.viewport);
            } else {
                map.map.setCenter(place.geometry.location);
                map.map.setZoom(17);  // Why 17? Because it looks good.
            }

            var country_code = 'CZ',
                country_name = '';
            if (place.address_components) {
                var address = place.address_components;
                for (var j = 0; j <= address.length; j++) {
                    if (address[j] && address[j].types[0] === 'country') {
                        country_code = address[j].short_name;
                        country_name = address[j].long_name;
                    }
                }

            }
            infowindow.open(map.map);
            infowindow.close();

            if ($.support.pjax) {
                $.pjax({url: '/' + country_code, container: event_list_container});
                $(document).on('pjax:success', function () {
                    $('#country').html(country_name);
                });

            }
        });
    }
    function zoomCountry(current_country) {
        var zoomgeocoder = new google.maps.Geocoder();
        zoomgeocoder.geocode({'address': current_country}, function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                var ne = results[0].geometry.viewport.getNorthEast();
                var sw = results[0].geometry.viewport.getSouthWest();
                map.map.fitBounds(results[0].geometry.viewport);
                map.map.setCenter(results[0].geometry.location);
				$("#country").html(current_country);
            }
        });
    }

    function initialize(events, lon, lan) {
        map = createMap(events, lon, lan, 4);
        setAutocomplete();
		console.log(window.location.hash);
        if (location.pathname !== "/") {
        var current_country = document.getElementById('country').innerHTML;
        zoomCountry(current_country);
        }
    }

    var search_events_handler = function () {
        var serch_query_input = $('#search-event'),
            search_event_btn = $('search-btn');

        search_event_btn.on('click', function (e) {
            e.preventDefault();
        });

    };

    var init = function (events, lon, lan) {

        $(function () {
            // Initialize map on front page
            google.maps.event.addDomListener(window, 'load', function () {
                initialize(events, lon, lan);
            });

            search_events_handler();

        });
    };

    Codeweek.Index = {};
    Codeweek.Index.init = init;

	$(".countryflag").click(function(sender){
		zoomCountry(sender.currentTarget.innerText);
		document.location.href = "#!" + sender.currentTarget.id;
	});

}(jQuery, Codeweek));

<|endoftext|>