<commit_before>var Backbone = require('backbone');
var _ = require('underscore');
var Utils = require('../helpers/utils');
var UserModel = require('./user-model');
var OrganizationModel = require('./organization-model');
var GroupModel = require('./group-model');
var ACLItemModel = require('./acl-item-model');
var READ_ONLY = 'r';
var READ_WRITE = 'rw';

/**
 * manages a cartodb permission object, it contains:
 * - owner: an UserModel instance
 * - acl: a collection which includes the user and their permission.
 *
 *   see https://github.com/Vizzuality/cartodb-management/wiki/multiuser-REST-API#permissions-object
 *
 *   this object is not created to work alone, it should be a member of
 *   an object like visualization table
 *
 */
var PermissionModel = module.exports = Backbone.Model.extend({
  urlRoot: function () {
    var baseUrl = this._configModel.get('base_url');
    var version = this._configModel.urlVersion('perm');
    return baseUrl + '/api/' + version + '/perm';
  },

  initialize: function (attrs, opts) {
    if (!opts.configModel) throw new Error('configModel is required');

    this._configModel = opts.configModel;
    this.acl = new Backbone.Collection();
    this.owner = opts._userModel;
    this._generateOwner();
    this._generateAcl();
    this._initBinds();
  },

  _initBinds: function () {
    this.bind('change:owner', this._generateOwner, this);
    this.bind('change:acl', this._generateAcl, this);
  },

  _generateOwner: function () {
    if (!this.owner) {
      this.owner = new UserModel(null, {
        configModel: this._configModel
      });
    }
    this.owner.set(this.get('owner'));
  },

  getOwner: function () {
    return this.owner;
  },

  _generateAcl: function () {
    var self = this;
    this.acl.reset([], { silent: true });
    _.each(this.get('acl'), function (aclItem) {
      var model;
      switch (aclItem.type) {
        case 'user':
          model = new UserModel(aclItem.entity, {
            configModel: self._configModel
          });
          break;
        case 'org':
          model = new OrganizationModel(aclItem.entity, {
            configModel: self._configModel
          });
          break;
        case 'group':
          model = new GroupModel(aclItem.entity, {
            configModel: self._configModel
          });
          break;
        default:
          throw new Error('Unknown ACL item type: ' + aclItem.type);
      }
      this._grantAccess(model, aclItem.access);
    }, this);
  },

  cleanPermissions: function () {
    this.acl.reset();
  },

  hasAccess: function (model) {
    // Having at least read access is the same as having any access
    return this.hasReadAccess(model);
  },

  hasReadAccess: function (model) {
    // If there is a representable ACL item it must be one of at least READ_ONLY access
    return !!this.findRepresentableAclItem(model);
  },

  hasWriteAccess: function (model) {
    var access = Utils.result(this.findRepresentableAclItem(model), 'get', 'access');
    return access === READ_WRITE;
  },

  canChangeReadAccess: function (model) {
    return this._canChangeAccess(model);
  },

  canChangeWriteAccess: function (model) {
    return (!model.isBuilder || model.isBuilder()) && this._canChangeAccess(model, function (representableAclItem) {
      return Utils.result(representableAclItem, 'get', 'access') !== READ_WRITE;
    });
  },

  _canChangeAccess: function (model) {
    var representableAclItem = this.findRepresentableAclItem(model);
    return this.isOwner(model) || !representableAclItem ||
    representableAclItem === this._ownAclItem(model) || Utils.result(arguments, 1, representableAclItem) || false;
  },

  grantWriteAccess: function (model) {
    this._grantAccess(model, READ_WRITE);
  },

  grantReadAccess: function (model) {
    this._grantAccess(model, READ_ONLY);
  },

  revokeWriteAccess: function (model) {
    // Effectively "downgrades" to READ_ONLY
    this.grantReadAccess(model);
  },

  /**
   * Revokes access to a set of items
   * @param {Object} model A single model or an array of models
   */
  revokeAccess: function (model) {
    var aclItem = this._ownAclItem(model);
    if (aclItem) {
      this.acl.remove(aclItem);
    }
  },

  isOwner: function (model) {
    return _.result(this.owner, 'id') === _.result(model, 'id');
  },

  toJSON: function () {
    return {
      entity: this.get('entity'),
      acl: this.acl.toJSON()
    };
  },

  getUsersWithAnyPermission: function () {
    return this.acl.chain()
      .filter(this._hasTypeUser)
      .map(this._getEntity)
      .value();
  },

  isSharedWithOrganization: function () {
    return this.acl.any(this._hasTypeOrg);
  },

  clone: function () {
    var attrs = _.clone(this.attributes);
    delete attrs.id;
    return new PermissionModel(attrs, {
      configModel: this._configModel
    });
  },

  /**
   * Overwrite this ACL list from other permission object
   * @param otherPermission {Object} instance of PermissionModel
   */
  overwriteAcl: function (otherPermission) {
    this.acl.reset(otherPermission.acl.models);
  },

  // Note that this may return an inherited ACL item
  // use ._ownAclItem instead if only model's own is wanted (if there is any)
  findRepresentableAclItem: function (model) {
    if (this.isOwner(model)) {
      return this._newAclItem(model, READ_WRITE);
    } else {
      var checkList = ['_ownAclItem', '_organizationAclItem', '_mostPrivilegedGroupAclItem'];

      return this._findMostPrivilegedAclItem(checkList, function (fnName) {
        return this[fnName](model);
      });
    }
  },

  _hasTypeUser: function (m) {
    return m.get('type') === 'user';
  },

  _getEntity: function (m) {
    return m.get('entity');
  },

  _hasTypeOrg: function (m) {
    return m.get('type') === 'org';
  },

  _isOrganization: function (object) {
    return object instanceof OrganizationModel;
  },

  _ownAclItem: function (model) {
    if (!model || !_.isFunction(model.isNew)) {
      console.log('model is required to find an ACL item');
    }

    if (!model.isNew()) {
      return this.acl.find(function (aclItem) {
        return aclItem.get('entity').id === model.id;
      });
    }
  },

  _organizationAclItem: function (m) {
    // try to get the organization from the user groups collection,
    // then from the user model (Editor),
    // and finally from the user model (Builder)
    var org = _.result(m.collection, 'organization') || m.organization || m.get('organization');

    if (org) {
      return this._ownAclItem(org);
    }
  },

  _mostPrivilegedGroupAclItem: function (m) {
    var groups = _.result(m.groups, 'models');

    if (groups) {
      return this._findMostPrivilegedAclItem(groups, this._ownAclItem);
    }
  },

  /**
   * Iterates over a items in given list using the iteratee, stops and returns when found the ACL item with best access (i.e. READ_WRITE), or the
   * list is completed.
   * @param {Array} list
   * @param {Function} iteratee that takes an item from list and returns an access
   *   iteratee is called in context of this model.
   * @Return {String} 'r', 'rw', or undefined if there were no access for given item
   */
  _findMostPrivilegedAclItem: function (list, iteratee) {
    var aclItem;
    for (var i = 0, x = list[i]; x && Utils.result(aclItem, 'get', 'access') !== READ_WRITE; x = list[++i]) {
      // Keep last ACL item if iteratee returns nothing
      aclItem = iteratee.call(this, x) || aclItem;
    }
    return aclItem;
  },

  /**
   * Grants access to a set of items
   * @param {Object} model
   * @param {String} access can take the following values:
   * - 'r': read only
   * - 'rw': read and write permission
   */
  _grantAccess: function (model, access) {
    var aclItem = this._ownAclItem(model);
    if (aclItem) {
      aclItem.set('access', access);
    } else {
      aclItem = this._newAclItem(model, access);
      if (aclItem.isValid()) {
        this.acl.add(aclItem);
      } else {
        throw new Error(access + ' is not a valid ACL access');
      }
    }
  },

  _newAclItem: function (model, access) {
    var type;
    if (model instanceof UserModel) {
      type = 'user';
    } else if (model instanceof GroupModel) {
      type = 'group';
    } else if (this._isOrganization(model)) {
      type = 'org';
    } else {
      throw new Error('model not recognized as a valid ACL entity ' + model);
    }

    return new ACLItemModel({
      type: type,
      entity: model,
      access: access
    });
  }
});

exports.READ_ONLY = READ_ONLY;
exports.READ_WRITE = READ_WRITE;
<commit_msg>fix org model<commit_after>var Backbone = require('backbone');
var _ = require('underscore');
var Utils = require('../helpers/utils');
var UserModel = require('./user-model');
var OrganizationModel = require('./organization-model');
var GroupModel = require('./group-model');
var ACLItemModel = require('./acl-item-model');
var READ_ONLY = 'r';
var READ_WRITE = 'rw';

/**
 * manages a cartodb permission object, it contains:
 * - owner: an UserModel instance
 * - acl: a collection which includes the user and their permission.
 *
 *   see https://github.com/Vizzuality/cartodb-management/wiki/multiuser-REST-API#permissions-object
 *
 *   this object is not created to work alone, it should be a member of
 *   an object like visualization table
 *
 */
var PermissionModel = module.exports = Backbone.Model.extend({
  urlRoot: function () {
    var baseUrl = this._configModel.get('base_url');
    var version = this._configModel.urlVersion('perm');
    return baseUrl + '/api/' + version + '/perm';
  },

  initialize: function (attrs, opts) {
    if (!opts.configModel) throw new Error('configModel is required');

    this._configModel = opts.configModel;
    this.acl = new Backbone.Collection();
    this.owner = opts._userModel;
    this._generateOwner();
    this._generateAcl();
    this._initBinds();
  },

  _initBinds: function () {
    this.bind('change:owner', this._generateOwner, this);
    this.bind('change:acl', this._generateAcl, this);
  },

  _generateOwner: function () {
    if (!this.owner) {
      this.owner = new UserModel(null, {
        configModel: this._configModel
      });
    }
    this.owner.set(this.get('owner'));
  },

  getOwner: function () {
    return this.owner;
  },

  _generateAcl: function () {
    var self = this;
    this.acl.reset([], { silent: true });
    _.each(this.get('acl'), function (aclItem) {
      var model;
      switch (aclItem.type) {
        case 'user':
          model = new UserModel(aclItem.entity, {
            configModel: self._configModel
          });
          break;
        case 'org':
          model = new OrganizationModel(aclItem.entity, {
            configModel: self._configModel
          });
          break;
        case 'group':
          model = new GroupModel(aclItem.entity, {
            configModel: self._configModel
          });
          break;
        default:
          throw new Error('Unknown ACL item type: ' + aclItem.type);
      }
      this._grantAccess(model, aclItem.access);
    }, this);
  },

  cleanPermissions: function () {
    this.acl.reset();
  },

  hasAccess: function (model) {
    // Having at least read access is the same as having any access
    return this.hasReadAccess(model);
  },

  hasReadAccess: function (model) {
    // If there is a representable ACL item it must be one of at least READ_ONLY access
    return !!this.findRepresentableAclItem(model);
  },

  hasWriteAccess: function (model) {
    var access = Utils.result(this.findRepresentableAclItem(model), 'get', 'access');
    return access === READ_WRITE;
  },

  canChangeReadAccess: function (model) {
    return this._canChangeAccess(model);
  },

  canChangeWriteAccess: function (model) {
    return (!model.isBuilder || model.isBuilder()) && this._canChangeAccess(model, function (representableAclItem) {
      return Utils.result(representableAclItem, 'get', 'access') !== READ_WRITE;
    });
  },

  _canChangeAccess: function (model) {
    var representableAclItem = this.findRepresentableAclItem(model);
    return this.isOwner(model) || !representableAclItem ||
    representableAclItem === this._ownAclItem(model) || Utils.result(arguments, 1, representableAclItem) || false;
  },

  grantWriteAccess: function (model) {
    this._grantAccess(model, READ_WRITE);
  },

  grantReadAccess: function (model) {
    this._grantAccess(model, READ_ONLY);
  },

  revokeWriteAccess: function (model) {
    // Effectively "downgrades" to READ_ONLY
    this.grantReadAccess(model);
  },

  /**
   * Revokes access to a set of items
   * @param {Object} model A single model or an array of models
   */
  revokeAccess: function (model) {
    var aclItem = this._ownAclItem(model);
    if (aclItem) {
      this.acl.remove(aclItem);
    }
  },

  isOwner: function (model) {
    return _.result(this.owner, 'id') === _.result(model, 'id');
  },

  toJSON: function () {
    return {
      entity: this.get('entity'),
      acl: this.acl.toJSON()
    };
  },

  getUsersWithAnyPermission: function () {
    return this.acl.chain()
      .filter(this._hasTypeUser)
      .map(this._getEntity)
      .value();
  },

  isSharedWithOrganization: function () {
    return this.acl.any(this._hasTypeOrg);
  },

  clone: function () {
    var attrs = _.clone(this.attributes);
    delete attrs.id;
    return new PermissionModel(attrs, {
      configModel: this._configModel
    });
  },

  /**
   * Overwrite this ACL list from other permission object
   * @param otherPermission {Object} instance of PermissionModel
   */
  overwriteAcl: function (otherPermission) {
    this.acl.reset(otherPermission.acl.models);
  },

  // Note that this may return an inherited ACL item
  // use ._ownAclItem instead if only model's own is wanted (if there is any)
  findRepresentableAclItem: function (model) {
    if (this.isOwner(model)) {
      return this._newAclItem(model, READ_WRITE);
    } else {
      var checkList = ['_ownAclItem', '_organizationAclItem', '_mostPrivilegedGroupAclItem'];

      return this._findMostPrivilegedAclItem(checkList, function (fnName) {
        return this[fnName](model);
      });
    }
  },

  _hasTypeUser: function (m) {
    return m.get('type') === 'user';
  },

  _getEntity: function (m) {
    return m.get('entity');
  },

  _hasTypeOrg: function (m) {
    return m.get('type') === 'org';
  },

  _isOrganization: function (object) {
    return object instanceof OrganizationModel;
  },

  _ownAclItem: function (model) {
    if (!model || !_.isFunction(model.isNew)) {
      console.log('model is required to find an ACL item');
    }

    if (!model.isNew()) {
      return this.acl.find(function (aclItem) {
        return aclItem.get('entity').id === model.id;
      });
    }
  },

  _organizationAclItem: function (m) {
    // try to get the organization from the user groups collection,
    // then from the user model (Editor),
    // and finally from the user model (Builder)
    var org = _.result(m.collection, 'organization') || m.organization || m._organizationModel;

    if (org) {
      return this._ownAclItem(org);
    }
  },

  _mostPrivilegedGroupAclItem: function (m) {
    var groups = _.result(m.groups, 'models');

    if (groups) {
      return this._findMostPrivilegedAclItem(groups, this._ownAclItem);
    }
  },

  /**
   * Iterates over a items in given list using the iteratee, stops and returns when found the ACL item with best access (i.e. READ_WRITE), or the
   * list is completed.
   * @param {Array} list
   * @param {Function} iteratee that takes an item from list and returns an access
   *   iteratee is called in context of this model.
   * @Return {String} 'r', 'rw', or undefined if there were no access for given item
   */
  _findMostPrivilegedAclItem: function (list, iteratee) {
    var aclItem;
    for (var i = 0, x = list[i]; x && Utils.result(aclItem, 'get', 'access') !== READ_WRITE; x = list[++i]) {
      // Keep last ACL item if iteratee returns nothing
      aclItem = iteratee.call(this, x) || aclItem;
    }
    return aclItem;
  },

  /**
   * Grants access to a set of items
   * @param {Object} model
   * @param {String} access can take the following values:
   * - 'r': read only
   * - 'rw': read and write permission
   */
  _grantAccess: function (model, access) {
    var aclItem = this._ownAclItem(model);
    if (aclItem) {
      aclItem.set('access', access);
    } else {
      aclItem = this._newAclItem(model, access);
      if (aclItem.isValid()) {
        this.acl.add(aclItem);
      } else {
        throw new Error(access + ' is not a valid ACL access');
      }
    }
  },

  _newAclItem: function (model, access) {
    var type;
    if (model instanceof UserModel) {
      type = 'user';
    } else if (model instanceof GroupModel) {
      type = 'group';
    } else if (this._isOrganization(model)) {
      type = 'org';
    } else {
      throw new Error('model not recognized as a valid ACL entity ' + model);
    }

    return new ACLItemModel({
      type: type,
      entity: model,
      access: access
    });
  }
});

exports.READ_ONLY = READ_ONLY;
exports.READ_WRITE = READ_WRITE;
<|endoftext|>


<commit_before>$(document).ready(function(){

   /*
    * jQuery simple and accessible hide-show system (collapsible regions), using ARIA
    * Website: http://a11y.nicolas-hoffmann.net/hide-show/
    * License MIT: https://github.com/nico3333fr/jquery-accessible-hide-show-aria/blob/master/LICENSE
    */
   // loading expand paragraphs
   // these are recommended settings by a11y experts. You may update to fulfill your needs, but be sure of what you’re doing.
   var attr_control = 'data-controls',
       attr_expanded = 'aria-expanded',
       attr_labelledby = 'data-labelledby',
       attr_hidden = 'data-hidden',
       $expandmore = $('.js-expandmore'),
       $to_expand = $('.js-to_expand'),
       $body = $('body'),
       delay = 1500;

   if ( $expandmore.length  &&  $to_expand.length ) { // if there are at least one :)
      $expandmore.each( function(index_to_expand) {
          var $this = $(this) ,
              index_lisible = index_to_expand+1,
              options = $this.data(),
              $hideshow_prefix_classes = typeof options.hideshowPrefixClass !== 'undefined' ? options.hideshowPrefixClass + '-' : '',
              $to_expand = $this.next(".js-to_expand"),
              $expandmore_text = $this.html();

          $this.html( '<button class="' + $hideshow_prefix_classes + 'expandmore__button js-expandmore-button">' + $expandmore_text + '</button>' );
          $button = $this.children('.js-expandmore-button');

          $to_expand.addClass( $hideshow_prefix_classes + 'expandmore__to_expand' ).stop().delay( delay ).queue( function() {
            var $this = $(this);
            if ($this.hasClass('js-first_load')) {
               $this.removeClass('js-first_load');
            }
          });

          $button.attr('id', 'label_expand_' + index_lisible);
          $button.attr(attr_control, 'expand_' + index_lisible);
          $button.attr(attr_expanded, 'false');

          $to_expand.attr('id', 'expand_' + index_lisible);
          $to_expand.attr(attr_hidden, 'true');
          $to_expand.attr(attr_labelledby, 'label_expand_' + index_lisible);

          // quick tip to open
          if ($to_expand.hasClass('is-opened') ){
             $button.addClass('is-opened').attr(attr_expanded, 'true');
             $to_expand.removeClass('is-opened').removeAttr(attr_hidden);
          }

      });

   }

   $body.on( 'click', '.js-expandmore-button', function( event ) {
      var $this = $(this),
          $destination = $( '#' + $this.attr(attr_control) );

      if ($this.attr(attr_expanded) === 'false') {
          $this.addClass('is-opened').attr(attr_expanded, 'true');
          $destination.removeAttr(attr_hidden);
         }
         else {
              $this.removeClass('is-opened').attr(attr_expanded, 'false');
              $destination.attr(attr_hidden, 'true');
              }

      event.preventDefault();

   });

   $body.on( 'click keydown', '.js-expandmore', function( event ) {
      var $this = $(this),
          $target = $(event.target),
          $button_in = $this.find( '.js-expandmore-button' );

      if ( !$target.is($button_in) && !$target.closest($button_in).length ) {

          if ( event.type == 'click' ){
              $button_in.trigger('click');
              return false;
              }
          if ( event.type == 'keydown' && (event.keyCode==13 || event.keyCode==32 )  ){
              $button_in.trigger('click');
              return false;
              }

          }

   });

});
<commit_msg>Avoid WordPress jQuery conflict mode<commit_after>jQuery(document).ready(function($){

   /*
    * jQuery simple and accessible hide-show system (collapsible regions), using ARIA
    * Website: http://a11y.nicolas-hoffmann.net/hide-show/
    * License MIT: https://github.com/nico3333fr/jquery-accessible-hide-show-aria/blob/master/LICENSE
    */
   // loading expand paragraphs
   // these are recommended settings by a11y experts. You may update to fulfill your needs, but be sure of what you’re doing.
   var attr_control = 'data-controls',
       attr_expanded = 'aria-expanded',
       attr_labelledby = 'data-labelledby',
       attr_hidden = 'data-hidden',
       $expandmore = $('.js-expandmore'),
       $to_expand = $('.js-to_expand'),
       $body = $('body'),
       delay = 1500;

   if ( $expandmore.length  &&  $to_expand.length ) { // if there are at least one :)
      $expandmore.each( function(index_to_expand) {
          var $this = $(this) ,
              index_lisible = index_to_expand+1,
              options = $this.data(),
              $hideshow_prefix_classes = typeof options.hideshowPrefixClass !== 'undefined' ? options.hideshowPrefixClass + '-' : '',
              $to_expand = $this.next(".js-to_expand"),
              $expandmore_text = $this.html();

          $this.html( '<button class="' + $hideshow_prefix_classes + 'expandmore__button js-expandmore-button">' + $expandmore_text + '</button>' );
          $button = $this.children('.js-expandmore-button');

          $to_expand.addClass( $hideshow_prefix_classes + 'expandmore__to_expand' ).stop().delay( delay ).queue( function() {
            var $this = $(this);
            if ($this.hasClass('js-first_load')) {
               $this.removeClass('js-first_load');
            }
          });

          $button.attr('id', 'label_expand_' + index_lisible);
          $button.attr(attr_control, 'expand_' + index_lisible);
          $button.attr(attr_expanded, 'false');

          $to_expand.attr('id', 'expand_' + index_lisible);
          $to_expand.attr(attr_hidden, 'true');
          $to_expand.attr(attr_labelledby, 'label_expand_' + index_lisible);

          // quick tip to open
          if ($to_expand.hasClass('is-opened') ){
             $button.addClass('is-opened').attr(attr_expanded, 'true');
             $to_expand.removeClass('is-opened').removeAttr(attr_hidden);
          }

      });

   }

   $body.on( 'click', '.js-expandmore-button', function( event ) {
      var $this = $(this),
          $destination = $( '#' + $this.attr(attr_control) );

      if ($this.attr(attr_expanded) === 'false') {
          $this.addClass('is-opened').attr(attr_expanded, 'true');
          $destination.removeAttr(attr_hidden);
         }
         else {
              $this.removeClass('is-opened').attr(attr_expanded, 'false');
              $destination.attr(attr_hidden, 'true');
              }

      event.preventDefault();

   });

   $body.on( 'click keydown', '.js-expandmore', function( event ) {
      var $this = $(this),
          $target = $(event.target),
          $button_in = $this.find( '.js-expandmore-button' );

      if ( !$target.is($button_in) && !$target.closest($button_in).length ) {

          if ( event.type == 'click' ){
              $button_in.trigger('click');
              return false;
              }
          if ( event.type == 'keydown' && (event.keyCode==13 || event.keyCode==32 )  ){
              $button_in.trigger('click');
              return false;
              }

          }

   });

});
<|endoftext|>


<commit_before>// Load in our dependencies
var fs = require('fs');
var readVendorFile = function (filepath) { return fs.readFileSync(__dirname + '/../vendor/' + filepath, 'utf8').trim(); };

// Load in our stop data
var csvStopTimesStr = readVendorFile('sfmta-60/stop_times.txt');
<commit_msg>Grabbed our data<commit_after>// Load in our dependencies
var fs = require('fs');
var Papa = require('papaparse');

// Define our helpers
// TODO: Polish our helpers
function parseCsvStr(csvStr) {
  var results = Papa.parse(csvStr, {
    header: true
  });
  if (results.errors.length) {
    console.error('Error encountered', results.errors[0]);
    throw new Error(results.errors[0].message);
  }
  return results.data;
}
function readVendorFile(filepath) {
  return fs.readFileSync(__dirname + '/vendor/' + filepath, 'utf8').trim();
}

// Load in our stop data
var csvStopTimesStr = readVendorFile('sfmta-60/stop_times.txt');
console.log('start...');
var stopTimes = parseCsvStr(csvStopTimesStr);
console.log('stop');

console.log(stopTimes.slice(0, 10));
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { I18nHelper } from '/imports/helpers/i18n';
import {ReactiveVar} from 'meteor/reactive-var';

let supportedLocales = new ReactiveVar([]);

Template.localeDialog.onCreated(function () {
    Meteor.call('getAvailableLocales',
        function(error, result){
            if(error){
                console.log('Error: No supported language locales reported by server.');
            }else{
                supportedLocales.set(result);
            }
        }
    );
});

Template.localeDialog.helpers({
    'supportedLocales': function () {
        return supportedLocales.get();
    }
});

Template.localeDialog.events({
    'submit #frmDlgSetLocale'(evt, tmpl) {
        evt.preventDefault();

        const newLoc = tmpl.find('#selLocale').value;
        I18nHelper.setLanguageLocale(newLoc);
        tmpl.$('#dlgLocale').modal('hide');
    },

    'show.bs.modal #dlgLocale': function (evt, tmpl) {
        // preselect the current locale, if user is logged in
        const loc = I18nHelper.getLanguageLocale();
        tmpl.find('#loc-'+loc).selected = true;
    },
});
<commit_msg>i18n Fix: Exception if set language not found in select control options We now fallback to 'en' if 'en-US' not an option.<commit_after>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { I18nHelper } from '/imports/helpers/i18n';
import {ReactiveVar} from 'meteor/reactive-var';

let supportedLocales = new ReactiveVar([]);

Template.localeDialog.onCreated(function () {
    Meteor.call('getAvailableLocales',
        function(error, result){
            if(error){
                console.log('Error: No supported language locales reported by server.');
            }else{
                supportedLocales.set(result);
            }
        }
    );
});

Template.localeDialog.helpers({
    'supportedLocales': function () {
        return supportedLocales.get();
    }
});

Template.localeDialog.events({
    'submit #frmDlgSetLocale'(evt, tmpl) {
        evt.preventDefault();

        const newLoc = tmpl.find('#selLocale').value;
        I18nHelper.setLanguageLocale(newLoc);
        tmpl.$('#dlgLocale').modal('hide');
    },

    'show.bs.modal #dlgLocale': function (evt, tmpl) {
        // preselect the current locale, if user is logged in
        let locID = '#loc-' + I18nHelper.getLanguageLocale();       // might be 'en-US'
        const select = tmpl.find(locID);
        if (select) {
            select.selected = true;
        } else {
            locID = '#loc-' + I18nHelper.getLanguageLocale().substr(0,2);   // fallback: try 'en'
            const select = tmpl.find(locID);
            if (select) {
                select.selected = true;
            }
            console.log('Could not find select option: >'+ locID+'<');
        }
    },
});
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/core/Transport", "Tone/core/Type", "Tone/core/TimelineState"], function (Tone) {

	"use strict";

	/**
	 *  @class  Tone.Event provides a callback for a single, repeatable
	 *          event along the timeline.
	 *
	 *  @param {function} callback The callback to invoke at the time.
	 *  @param {*} value The value or values which should be passed to
	 *                      the callback function on invocation.
	 *  @example
	 * var chord = new Tone.Event(function(time, chord){
	 * 	//the chord as well as the exact time of the event
	 * 	//are passed in as arguments to the callback function
	 * }, "Dm");
	 * //start the chord at the beginning of the transport timeline
	 * chord.start();
	 * //loop it every measure for 8 measures
	 * chord.loop = 8;
	 * chord.loopEnd = "1m";
	 */
	Tone.Event = function(){

		var options = this.optionsObject(arguments, ["callback", "value"], Tone.Event.defaults);

		/**
		 *  Loop value
		 *  @type  {Boolean|Positive}
		 *  @private
		 */
		this._loop = options.loop;

		/**
		 *  The callback to invoke.
		 *  @type  {Function}
		 */
		this.callback = options.callback;

		/**
		 *  The value which is passed to the
		 *  callback function.
		 *  @type  {*}
		 *  @private
		 */
		this.value = options.value;

		/**
		 *  When the note is scheduled to start.
		 *  @type  {Number}
		 *  @private
		 */
		this._loopStart = 0;

		/**
		 *  When the note is scheduled to start.
		 *  @type  {Number}
		 *  @private
		 */
		this._loopEnd = 0;

		/**
		 *  Tracks the scheduled events
		 *  @type {Tone.TimelineState}
		 *  @private
		 */
		this._state = new Tone.TimelineState(Tone.State.Stopped);

		/**
		 *  The playback speed of the note. A speed of 1
		 *  is no change.
		 *  @private
		 *  @type {Positive}
		 */
		this._playbackRate = 1;

		/**
		 *  A delay time from when the event is scheduled to start
		 *  @type {Ticks}
		 *  @private
		 */
		this._startDelay = 0;

		/**
		 *  The probability that the callback will be invoked
		 *  at the scheduled time.
		 *  @type {NormalRange}
		 */
		this.probability = options.probability;

		/**
		 *  Random variation +/-0.01s to the scheduled time.
		 *  Or give it a time value which it will randomize by.
		 *  @type {Boolean|Time}
		 */
		this.humanize = options.humanize;

		/**
		 *  If the part is inactive and does
		 *  not invoke the callback function.
		 *  @type {Boolean}
		 */
		this.mute = options.mute;

		//set the initial values
		this.loopStart = options.loopStart;
		this.loopEnd = options.loopEnd;
		this.playbackRate = options.playbackRate;
	};

	Tone.extend(Tone.Event);

	/**
	 *  The default values
	 *  @type  {Object}
	 *  @const
	 */
	Tone.Event.defaults = {
		"callback" : Tone.noOp,
		"loop" : false,
		"loopEnd" : "1m",
		"loopStart" : 0,
		"playbackRate" : 1,
		"value" : null,
		"probability" : 1,
		"mute" : false,
		"humanize" : false,
	};

	/**
	 *  Reschedule all of the events along the timeline
	 *  with the updated values.
	 *  @param {Time} after Only reschedules events after the given time.
	 *  @return  {Tone.Event}  this
	 *  @private
	 */
	Tone.Event.prototype._rescheduleEvents = function(after){
		//if no argument is given, schedules all of the events
		after = this.defaultArg(after, -1);
		this._state.forEachFrom(after, function(event){
			var duration;
			if (event.state === Tone.State.Started){
				if (!this.isUndef(event.id)){
					Tone.Transport.clear(event.id);
				}
				var startTick = event.time + Math.round(this._startDelay / this._playbackRate);
				if (this._loop){
					duration = Infinity;
					if (this.isNumber(this._loop)){
						duration =  (this._loop - 1) * this._getLoopDuration();
					}
					var nextEvent = this._state.getEventAfter(startTick);
					if (nextEvent !== null){
						duration = Math.min(duration, nextEvent.time - startTick);
					}
					//make it ticks
					if (duration !== Infinity){
						//schedule a stop since it's finite duration
						duration += "i";
					}
					event.id = Tone.Transport.scheduleRepeat(this._tick.bind(this), this._getLoopDuration().toString() + "i", startTick + "i", duration);
					if (duration !== Infinity){
						this.stop((startTick + 1) + "i + "+ duration);
					}
				} else {
					event.id = Tone.Transport.schedule(this._tick.bind(this), startTick + "i");
				}
			}
		}.bind(this));
		return this;
	};

	/**
	 *  Returns the playback state of the note, either "started" or "stopped".
	 *  @type {String}
	 *  @readOnly
	 *  @memberOf Tone.Event#
	 *  @name state
	 */
	Object.defineProperty(Tone.Event.prototype, "state", {
		get : function(){
			return this._state.getStateAtTime(Tone.Transport.ticks);
		}
	});

	/**
	 *  Start the note at the given time.
	 *  @param  {Time}  time  When the note should start.
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.start = function(time){
		time = this.toTicks(time);
		if (this._state.getStateAtTime(time) === Tone.State.Stopped){
			this._state.addEvent({
				"state" : Tone.State.Started,
				"time" : time,
				"id" : undefined,
			});
			this._rescheduleEvents(time);
		}
		return this;
	};

	/**
	 *  Stop the Note at the given time.
	 *  @param  {Time}  time  When the note should stop.
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.stop = function(time){
		time = this.toTicks(time);
		if (this._state.getStateAtTime(time) === Tone.State.Started){
			this._state.setStateAtTime(Tone.State.Stopped, time);
			var previousEvent = this._state.getEventBefore(time);
			var reschedulTime = time;
			if (previousEvent !== null){
				reschedulTime = previousEvent.time;
			}
			this._rescheduleEvents(reschedulTime);
		}
		return this;
	};

	/**
	 *  Cancel all scheduled events greater than or equal to the given time
	 *  @param  {Time}  [time=0]  The time after which events will be cancel.
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.cancel = function(time){
		time = this.defaultArg(time, -Infinity);
		time = this.toTicks(time);
		this._state.forEachFrom(time, function(event){
			Tone.Transport.clear(event.id);
		});
		this._state.cancel(time);
		return this;
	};

	/**
	 *  The callback function invoker. Also
	 *  checks if the Note is done playing
	 *  @param  {Number}  time  The time of the event in seconds
	 *  @private
	 */
	Tone.Event.prototype._tick = function(time){
		if (!this.mute && this._state.getStateAtTime(Tone.Transport.ticks) === Tone.State.Started){
			if (this.probability < 1 && Math.random() > this.probability){
				return;
			}
			if (this.humanize){
				var variation = 0.01;
				if (!this.isBoolean(this.humanize)){
					variation = this.toSeconds(this.humanize);
				}
				time += (Math.random() * 2 - 1) * variation;
			}
			this.callback(time, this.value);
		}
	};

	/**
	 *  Get the duration of the loop.
	 *  @return  {Ticks}
	 *  @private
	 */
	Tone.Event.prototype._getLoopDuration = function(){
		return Math.round((this._loopEnd - this._loopStart) / this._playbackRate);
	};

	/**
	 *  If the note should loop or not
	 *  between Tone.Event.loopStart and
	 *  Tone.Event.loopEnd. An integer
	 *  value corresponds to the number of
	 *  loops the Note does after it starts.
	 *  @memberOf Tone.Event#
	 *  @type {Boolean|Positive}
	 *  @name loop
	 */
	Object.defineProperty(Tone.Event.prototype, "loop", {
		get : function(){
			return this._loop;
		},
		set : function(loop){
			this._loop = loop;
			this._rescheduleEvents();
		}
	});

	/**
	 * 	The playback rate of the note. Defaults to 1.
	 *  @memberOf Tone.Event#
	 *  @type {Positive}
	 *  @name playbackRate
	 *  @example
	 * note.loop = true;
	 * //repeat the note twice as fast
	 * note.playbackRate = 2;
	 */
	Object.defineProperty(Tone.Event.prototype, "playbackRate", {
		get : function(){
			return this._playbackRate;
		},
		set : function(rate){
			this._playbackRate = rate;
			if (this._loop){
				this._rescheduleEvents();
			}
		}
	});

	/**
	 *  The loopEnd point determines when it will
	 *  loop if Tone.Event.loop is true.
	 *  @memberOf Tone.Event#
	 *  @type {Boolean|Positive}
	 *  @name loopEnd
	 */
	Object.defineProperty(Tone.Event.prototype, "loopEnd", {
		get : function(){
			return this.toNotation(this._loopEnd + "i");
		},
		set : function(loopEnd){
			this._loopEnd = this.toTicks(loopEnd);
			if (this._loop){
				this._rescheduleEvents();
			}
		}
	});

	/**
	 *  The loopStart point determines when it will
	 *  loop if Tone.Event.loop is true.
	 *  @memberOf Tone.Event#
	 *  @type {Boolean|Positive}
	 *  @name loopStart
	 */
	Object.defineProperty(Tone.Event.prototype, "loopStart", {
		get : function(){
			return this.toNotation(this._loopStart + "i");
		},
		set : function(loopStart){
			this._loopStart = this.toTicks(loopStart);
			if (this._loop){
				this._rescheduleEvents();
			}
		}
	});

	/**
	 *  The current progress of the loop interval.
	 *  Returns 0 if the atom is not started yet or the
	 *  atom is not set to loop.
	 *  @memberOf Tone.Event#
	 *  @type {NormalRange}
	 *  @name progress
	 *  @readOnly
	 */
	Object.defineProperty(Tone.Event.prototype, "progress", {
		get : function(){
			if (this._loop){
				var ticks = Tone.Transport.ticks;
				var lastEvent = this._state.getEvent(ticks);
				if (lastEvent !== null && lastEvent.state === Tone.State.Started){
					var loopDuration = this._getLoopDuration();
					var progress = (ticks - lastEvent.time) % loopDuration;
					return progress / loopDuration;
				} else {
					return 0;
				}
			} else {
				return 0;
			}
		}
	});

	/**
	 *  Clean up
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.dispose = function(){
		this.cancel();
		this._state.dispose();
		this._state = null;
		this.callback = null;
		this.value = null;
	};

	return Tone.Event;
});<commit_msg>uses a private startOffset to keep track of nested Events<commit_after>define(["Tone/core/Tone", "Tone/core/Transport", "Tone/core/Type", "Tone/core/TimelineState"], function (Tone) {

	"use strict";

	/**
	 *  @class  Tone.Event provides a callback for a single, repeatable
	 *          event along the timeline.
	 *
	 *  @param {function} callback The callback to invoke at the time.
	 *  @param {*} value The value or values which should be passed to
	 *                      the callback function on invocation.
	 *  @example
	 * var chord = new Tone.Event(function(time, chord){
	 * 	//the chord as well as the exact time of the event
	 * 	//are passed in as arguments to the callback function
	 * }, "Dm");
	 * //start the chord at the beginning of the transport timeline
	 * chord.start();
	 * //loop it every measure for 8 measures
	 * chord.loop = 8;
	 * chord.loopEnd = "1m";
	 */
	Tone.Event = function(){

		var options = this.optionsObject(arguments, ["callback", "value"], Tone.Event.defaults);

		/**
		 *  Loop value
		 *  @type  {Boolean|Positive}
		 *  @private
		 */
		this._loop = options.loop;

		/**
		 *  The callback to invoke.
		 *  @type  {Function}
		 */
		this.callback = options.callback;

		/**
		 *  The value which is passed to the
		 *  callback function.
		 *  @type  {*}
		 *  @private
		 */
		this.value = options.value;

		/**
		 *  When the note is scheduled to start.
		 *  @type  {Number}
		 *  @private
		 */
		this._loopStart = this.toTicks(options.loopStart);

		/**
		 *  When the note is scheduled to start.
		 *  @type  {Number}
		 *  @private
		 */
		this._loopEnd = this.toTicks(options.loopEnd);

		/**
		 *  Tracks the scheduled events
		 *  @type {Tone.TimelineState}
		 *  @private
		 */
		this._state = new Tone.TimelineState(Tone.State.Stopped);

		/**
		 *  The playback speed of the note. A speed of 1
		 *  is no change.
		 *  @private
		 *  @type {Positive}
		 */
		this._playbackRate = 1;

		/**
		 *  A delay time from when the event is scheduled to start
		 *  @type {Ticks}
		 *  @private
		 */
		this._startOffset = 0;

		/**
		 *  The probability that the callback will be invoked
		 *  at the scheduled time.
		 *  @type {NormalRange}
		 */
		this.probability = options.probability;

		/**
		 *  Random variation +/-0.01s to the scheduled time.
		 *  Or give it a time value which it will randomize by.
		 *  Note that if the value is too large, the humanized time
		 *  could aniticpate the current clock's time. For this
		 *  reason, the value should be kept below the clock's lookAhead time.
		 *  @type {Boolean|Time}
		 */
		this.humanize = options.humanize;

		/**
		 *  If the part is inactive and does
		 *  not invoke the callback function.
		 *  @type {Boolean}
		 */
		this.mute = options.mute;

		//set the initial values
		this.playbackRate = options.playbackRate;
	};

	Tone.extend(Tone.Event);

	/**
	 *  The default values
	 *  @type  {Object}
	 *  @const
	 */
	Tone.Event.defaults = {
		"callback" : Tone.noOp,
		"loop" : false,
		"loopEnd" : "1m",
		"loopStart" : 0,
		"playbackRate" : 1,
		"value" : null,
		"probability" : 1,
		"mute" : false,
		"humanize" : false,
	};

	/**
	 *  Reschedule all of the events along the timeline
	 *  with the updated values.
	 *  @param {Time} after Only reschedules events after the given time.
	 *  @return  {Tone.Event}  this
	 *  @private
	 */
	Tone.Event.prototype._rescheduleEvents = function(after){
		//if no argument is given, schedules all of the events
		after = this.defaultArg(after, -1);
		this._state.forEachFrom(after, function(event){
			var duration;
			if (event.state === Tone.State.Started){
				if (!this.isUndef(event.id)){
					Tone.Transport.clear(event.id);
				}
				var startTick = event.time + Math.round(this.startOffset / this._playbackRate);
				if (this._loop){
					duration = Infinity;
					if (this.isNumber(this._loop)){
						duration =  (this._loop - 1) * this._getLoopDuration();
					}
					var nextEvent = this._state.getEventAfter(startTick);
					if (nextEvent !== null){
						duration = Math.min(duration, nextEvent.time - startTick);
					}
					//make it ticks
					if (duration !== Infinity){
						//schedule a stop since it's finite duration
						duration += "i";
					}
					event.id = Tone.Transport.scheduleRepeat(this._tick.bind(this), this._getLoopDuration().toString() + "i", startTick + "i", duration);
					if (duration !== Infinity){
						this.stop((startTick + 1) + "i + "+ duration);
					}
				} else {
					event.id = Tone.Transport.schedule(this._tick.bind(this), startTick + "i");
				}
			}
		}.bind(this));
		return this;
	};

	/**
	 *  Returns the playback state of the note, either "started" or "stopped".
	 *  @type {String}
	 *  @readOnly
	 *  @memberOf Tone.Event#
	 *  @name state
	 */
	Object.defineProperty(Tone.Event.prototype, "state", {
		get : function(){
			return this._state.getStateAtTime(Tone.Transport.ticks);
		}
	});

	/**
	 *  The start from the scheduled start time
	 *  @type {Ticks}
	 *  @memberOf Tone.Event#
	 *  @name startOffset
	 *  @private
	 */
	Object.defineProperty(Tone.Event.prototype, "startOffset", {
		get : function(){
			return this._startOffset;
		},
		set : function(offset){
			this._startOffset = offset;
		}
	});

	/**
	 *  Start the note at the given time.
	 *  @param  {Time}  time  When the note should start.
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.start = function(time){
		time = this.toTicks(time);
		if (this._state.getStateAtTime(time) === Tone.State.Stopped){
			this._state.addEvent({
				"state" : Tone.State.Started,
				"time" : time,
				"id" : undefined,
			});
			this._rescheduleEvents(time);
		}
		return this;
	};

	/**
	 *  Stop the Note at the given time.
	 *  @param  {Time}  time  When the note should stop.
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.stop = function(time){
		time = this.toTicks(time);
		if (this._state.getStateAtTime(time) === Tone.State.Started){
			this._state.setStateAtTime(Tone.State.Stopped, time);
			var previousEvent = this._state.getEventBefore(time);
			var reschedulTime = time;
			if (previousEvent !== null){
				reschedulTime = previousEvent.time;
			}
			this._rescheduleEvents(reschedulTime);
		}
		return this;
	};

	/**
	 *  Cancel all scheduled events greater than or equal to the given time
	 *  @param  {Time}  [time=0]  The time after which events will be cancel.
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.cancel = function(time){
		time = this.defaultArg(time, -Infinity);
		time = this.toTicks(time);
		this._state.forEachFrom(time, function(event){
			Tone.Transport.clear(event.id);
		});
		this._state.cancel(time);
		return this;
	};

	/**
	 *  The callback function invoker. Also
	 *  checks if the Note is done playing
	 *  @param  {Number}  time  The time of the event in seconds
	 *  @private
	 */
	Tone.Event.prototype._tick = function(time){
		if (!this.mute && this._state.getStateAtTime(Tone.Transport.ticks) === Tone.State.Started){
			if (this.probability < 1 && Math.random() > this.probability){
				return;
			}
			if (this.humanize){
				var variation = 0.01;
				if (!this.isBoolean(this.humanize)){
					variation = this.toSeconds(this.humanize);
				}
				time += (Math.random() * 2 - 1) * variation;
			}
			this.callback(time, this.value);
		}
	};

	/**
	 *  Get the duration of the loop.
	 *  @return  {Ticks}
	 *  @private
	 */
	Tone.Event.prototype._getLoopDuration = function(){
		return Math.round((this._loopEnd - this._loopStart) / this._playbackRate);
	};

	/**
	 *  If the note should loop or not
	 *  between Tone.Event.loopStart and
	 *  Tone.Event.loopEnd. An integer
	 *  value corresponds to the number of
	 *  loops the Note does after it starts.
	 *  @memberOf Tone.Event#
	 *  @type {Boolean|Positive}
	 *  @name loop
	 */
	Object.defineProperty(Tone.Event.prototype, "loop", {
		get : function(){
			return this._loop;
		},
		set : function(loop){
			this._loop = loop;
			this._rescheduleEvents();
		}
	});

	/**
	 * 	The playback rate of the note. Defaults to 1.
	 *  @memberOf Tone.Event#
	 *  @type {Positive}
	 *  @name playbackRate
	 *  @example
	 * note.loop = true;
	 * //repeat the note twice as fast
	 * note.playbackRate = 2;
	 */
	Object.defineProperty(Tone.Event.prototype, "playbackRate", {
		get : function(){
			return this._playbackRate;
		},
		set : function(rate){
			this._playbackRate = rate;
			this._rescheduleEvents();
		}
	});

	/**
	 *  The loopEnd point determines when it will
	 *  loop if Tone.Event.loop is true.
	 *  @memberOf Tone.Event#
	 *  @type {Boolean|Positive}
	 *  @name loopEnd
	 */
	Object.defineProperty(Tone.Event.prototype, "loopEnd", {
		get : function(){
			return this.toNotation(this._loopEnd + "i");
		},
		set : function(loopEnd){
			this._loopEnd = this.toTicks(loopEnd);
			if (this._loop){
				this._rescheduleEvents();
			}
		}
	});

	/**
	 *  The loopStart point determines when it will
	 *  loop if Tone.Event.loop is true.
	 *  @memberOf Tone.Event#
	 *  @type {Boolean|Positive}
	 *  @name loopStart
	 */
	Object.defineProperty(Tone.Event.prototype, "loopStart", {
		get : function(){
			return this.toNotation(this._loopStart + "i");
		},
		set : function(loopStart){
			this._loopStart = this.toTicks(loopStart);
			if (this._loop){
				this._rescheduleEvents();
			}
		}
	});

	/**
	 *  The current progress of the loop interval.
	 *  Returns 0 if the atom is not started yet or the
	 *  atom is not set to loop.
	 *  @memberOf Tone.Event#
	 *  @type {NormalRange}
	 *  @name progress
	 *  @readOnly
	 */
	Object.defineProperty(Tone.Event.prototype, "progress", {
		get : function(){
			if (this._loop){
				var ticks = Tone.Transport.ticks;
				var lastEvent = this._state.getEvent(ticks);
				if (lastEvent !== null && lastEvent.state === Tone.State.Started){
					var loopDuration = this._getLoopDuration();
					var progress = (ticks - lastEvent.time) % loopDuration;
					return progress / loopDuration;
				} else {
					return 0;
				}
			} else {
				return 0;
			}
		}
	});

	/**
	 *  Clean up
	 *  @return  {Tone.Event}  this
	 */
	Tone.Event.prototype.dispose = function(){
		this.cancel();
		this._state.dispose();
		this._state = null;
		this.callback = null;
		this.value = null;
	};

	return Tone.Event;
});<|endoftext|>


<commit_before>var ttURL = 'http://127.0.0.1:5000/'

chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function(tabs) {
  summarize(tabs[0].url);
});

function summarize(url) {
  console.log(url)

  var xhr = new XMLHttpRequest();
  xhr.open("GET", ttURL + "summarize?url=" + url, true);

  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
      var res = JSON.parse(xhr.responseText);
    }
  }

  xhr.send()
}

// var xhr = new XMLHttpRequest();
// var response = null
// var defaultCount = 5

// xhr.open("GET", "http://127.0.0.1:5000/get/276", true);

// xhr.onreadystatechange = function() {
//   if (xhr.readyState == 4) {
//     // innerText does not let the attacker inject HTML elements.
//     // document.getElementById("content").innerText = xhr.responseText;

//     var res = JSON.parse(xhr.responseText);
//     response = res;

//     showSentences(defaultCount);
//   }
// }

// xhr.send();

// function showSentences(count) {
//   console.log(tabURL)
//   document.getElementById("content").innerText = ''

//   showRangeSlider(count);

//   sentences = response['sentences'];
//   sentences.sort(sortScore).reverse();
//   sentences = sentences.slice(0, count)
//   sentences.sort(sortOrder)

//   var ul = document.createElement('ul');

//   for(var i in sentences) {
//     var li = document.createElement('li');
//     li.appendChild(document.createTextNode(sentences[i].sentence));
//     ul.appendChild(li)
//   }

//   document.getElementById("content").appendChild(ul);
// }

// function showRangeSlider(count) {
//   var range = document.createElement('input');
//   range.id = 'sentencesRange'
//   range.type = 'range';
//   range.min = 1
//   range.max = response['sentences'].length;
//   range.step = 1
//   range.value = count

//   document.getElementById("content").appendChild(range);

//   range.onchange = function() {
//     showSentences(range.value)
//   }
// }

// function sortScore(a, b) {
//   if(a.score < b.score)
//     return -1;

//   if(a.score > b.score)
//     return 1

//   return 0;
// }

// function sortOrder(a, b) {
//   if(a.order < b.order)
//     return -1;

//   if(a.order > b.order)
//     return 1

//   return 0;
// }<commit_msg>lunch break<commit_after>var ttURL = 'http://127.0.0.1:5000/'

chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function(tabs) {
  summarize(tabs[0].url);
});

function summarize(url) {
  console.log(url)

  $.get(ttURL + "summarize", {url: url}, "json")
    .done(function(data) {
      checkSummary(data.id)
    })
    .fail(function(data) {
      alert(data.responseJSON.id)
    });

  // var xhr = new XMLHttpRequest();
  // xhr.open("GET", ttURL + "summarize?url=" + url, true);

  // xhr.onreadystatechange = function() {
  //   if (xhr.readyState == 4) {
  //     var res = JSON.parse(xhr.responseText);
  //   }
  // }

  // xhr.send()
}

function checkSummary(summid) {
  $.get(ttURL + 'get/' + summid, "json")
    .done(function(data) {
      alert(data.sentences)
    })
    .fail(function(data) {

    })
}

// var xhr = new XMLHttpRequest();
// var response = null
// var defaultCount = 5

// xhr.open("GET", "http://127.0.0.1:5000/get/276", true);

// xhr.onreadystatechange = function() {
//   if (xhr.readyState == 4) {
//     // innerText does not let the attacker inject HTML elements.
//     // document.getElementById("content").innerText = xhr.responseText;

//     var res = JSON.parse(xhr.responseText);
//     response = res;

//     showSentences(defaultCount);
//   }
// }

// xhr.send();

// function showSentences(count) {
//   console.log(tabURL)
//   document.getElementById("content").innerText = ''

//   showRangeSlider(count);

//   sentences = response['sentences'];
//   sentences.sort(sortScore).reverse();
//   sentences = sentences.slice(0, count)
//   sentences.sort(sortOrder)

//   var ul = document.createElement('ul');

//   for(var i in sentences) {
//     var li = document.createElement('li');
//     li.appendChild(document.createTextNode(sentences[i].sentence));
//     ul.appendChild(li)
//   }

//   document.getElementById("content").appendChild(ul);
// }

// function showRangeSlider(count) {
//   var range = document.createElement('input');
//   range.id = 'sentencesRange'
//   range.type = 'range';
//   range.min = 1
//   range.max = response['sentences'].length;
//   range.step = 1
//   range.value = count

//   document.getElementById("content").appendChild(range);

//   range.onchange = function() {
//     showSentences(range.value)
//   }
// }

// function sortScore(a, b) {
//   if(a.score < b.score)
//     return -1;

//   if(a.score > b.score)
//     return 1

//   return 0;
// }

// function sortOrder(a, b) {
//   if(a.order < b.order)
//     return -1;

//   if(a.order > b.order)
//     return 1

//   return 0;
// }<|endoftext|>


<commit_before>'use strict';

// MODULES //

var proc = require( './process.js' );

// EXPORTS //

module.exports = proc.nextTick; // TODO: polyfill
<commit_msg>Use setTimeout<commit_after>'use strict';

// MAIN //

/**
* Runs a function on a subsequent turn of the event loop.
*
* ## Notes
*
* * `process.nextTick` is only Node.js.
* * `setIntermediate` is non-standard.
* * Everything else is browser based (e.g., mutation observer, requestAnimationFrame, etc).
* * Only API which is universal is `setTimeout`.
* * Note that `0` is not actually `0ms`. Browser environments commonly have a minimum delay of `4ms`. This is acceptable. Here, the main intent of this function is to give the runtime a chance to run garbage collection, clear state, and tend to any other pending tasks before returning control to benchmark tasks. The larger aim (attainable or not) is to provide each benchmark run with as much of a fresh state as possible.
*
*
* @private
* @param {Function} fcn - function to run upon a subsequent turn of the event loop
*/
function nextTick( fcn ) {
	setTimeout( fcn, 0 );
} // end FUNCTION nextTick()

// EXPORTS //

module.exports = nextTick;
<|endoftext|>


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

'use strict';

/*
* The original C code, long comment, copyright, license, and constants are from [Cephes]{@link http://www.netlib.org/cephes/}.
*
* The implementation follows the original, but has been modified for JavaScript.
*/

/*
* COPYRIGHT
*
* Cephes Math Library Release 2.8:  June, 2000
* Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
*
*
* LICENSE
*
* The README [file]{@link http://netlib.sandia.gov/cephes/} reads:
*   > Some software in this archive may be from the book _Methods and Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster International, 1989) or from the Cephes Mathematical Library, a commercial product. In either event, it is copyrighted by the author. What you see here may be used freely but it comes with no support or guarantee.
*   > The two known misprints in the book are repaired here in the source listings for the gamma function and the incomplete beta integral.
*   > Stephen L. Moshier
*   > moshier@na-net.ornl.gov
*/

// MODULES //

var floor = require( '@stdlib/math/base/special/floor' );
var ldexp = require( '@stdlib/math/base/special/ldexp' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var MAXL10 = require( '@stdlib/constants/math/float64-max-base10-exponent' );
var MINL10 = require( '@stdlib/constants/math/float64-min-base10-exponent' );
var PINF = require( '@stdlib/constants/math/float64-pinf' );
var polyvalP = require( './polyval_p.js' );
var polyvalQ = require( './polyval_q.js' );

// VARIABLES //

var LOG210 = 3.32192809488736234787e0;
var LG102A = 3.01025390625000000000e-1;
var LG102B = 4.60503898119521373889e-6;

// MAIN //

/**
* Returns `10` raised to the `x` power.
*
* ## Method
*
* -   Range reduction is accomplished by expressing the argument as \\( 10^x = 2^n 10^f \\), with \\( |f| < 0.5 log_{10}(2) \\). The Pade' form
*
*     ```tex
*     1 + 2x \frac{P(x^2)}{Q(x^2) - P(x^2)}
*     ```
*
*     is used to approximate \\( 10^f \\).
*
*
* ## Notes
*
* -   Relative error:
*
*     | arithmetic | domain      | # trials | peak    | rms     |
*     |:----------:|:-----------:|:--------:|:-------:|:-------:|
*     | IEEE       | -307,+307   |  30000   | 2.2e-16 | 5.5e-17 |
*
*
* @param {number} x - input value
* @returns {number} function value
*
* @example
* var v = exp10( 3.0 );
* // returns 1000.0
*
* @example
* var v = exp10( -9.0 );
* // returns 1.0e-9
*
* @example
* var v = exp10( 0.0 );
* // returns 1.0
*
* @example
* var v = exp10( NaN );
* // returns NaN
*/
function exp10( x ) {
	var px;
	var xx;
	var n;

	if ( isnan( x ) ) {
		return x;
	}
	if ( x > MAXL10 ) {
		return PINF;
	}
	if ( x < MINL10 ) {
		return 0.0;
	}

	// Express 10^x = 10^g 2^n = 10^g 10^( n log10(2) ) = 10^( g + n log10(2) )
	px = floor( (LOG210*x) + 0.5 );
	n = px;
	x -= px * LG102A;
	x -= px * LG102B;

	// Rational approximation for exponential of the fractional part: 10^x = 1 + 2x P(x^2)/( Q(x^2) - P(x^2) )
	xx = x * x;
	px = x * polyvalP( xx );
	x = px / ( polyvalQ( xx ) - px );
	x = 1.0 + ldexp( x, 1 );

	// Multiply by power of 2:
	return ldexp( x, n );
}

// EXPORTS //

module.exports = exp10;
<commit_msg>Update license header<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* ## Notice
*
* The original C code, long comment, copyright, license, and constants are from [Cephes]{@link http://www.netlib.org/cephes}. The implementation follows the original, but has been modified for JavaScript.
*
* ```text
* Copyright 1984, 1991, 2000 by Stephen L. Moshier
*
* Some software in this archive may be from the book _Methods and Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster International, 1989) or from the Cephes Mathematical Library, a commercial product. In either event, it is copyrighted by the author. What you see here may be used freely but it comes with no support or guarantee.
*
* Stephen L. Moshier
* moshier@na-net.ornl.gov
* ```
*/

'use strict';

// MODULES //

var floor = require( '@stdlib/math/base/special/floor' );
var ldexp = require( '@stdlib/math/base/special/ldexp' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var MAXL10 = require( '@stdlib/constants/math/float64-max-base10-exponent' );
var MINL10 = require( '@stdlib/constants/math/float64-min-base10-exponent' );
var PINF = require( '@stdlib/constants/math/float64-pinf' );
var polyvalP = require( './polyval_p.js' );
var polyvalQ = require( './polyval_q.js' );

// VARIABLES //

var LOG210 = 3.32192809488736234787e0;
var LG102A = 3.01025390625000000000e-1;
var LG102B = 4.60503898119521373889e-6;

// MAIN //

/**
* Returns `10` raised to the `x` power.
*
* ## Method
*
* -   Range reduction is accomplished by expressing the argument as \\( 10^x = 2^n 10^f \\), with \\( |f| < 0.5 log_{10}(2) \\). The Pade' form
*
*     ```tex
*     1 + 2x \frac{P(x^2)}{Q(x^2) - P(x^2)}
*     ```
*
*     is used to approximate \\( 10^f \\).
*
*
* ## Notes
*
* -   Relative error:
*
*     | arithmetic | domain      | # trials | peak    | rms     |
*     |:----------:|:-----------:|:--------:|:-------:|:-------:|
*     | IEEE       | -307,+307   |  30000   | 2.2e-16 | 5.5e-17 |
*
*
* @param {number} x - input value
* @returns {number} function value
*
* @example
* var v = exp10( 3.0 );
* // returns 1000.0
*
* @example
* var v = exp10( -9.0 );
* // returns 1.0e-9
*
* @example
* var v = exp10( 0.0 );
* // returns 1.0
*
* @example
* var v = exp10( NaN );
* // returns NaN
*/
function exp10( x ) {
	var px;
	var xx;
	var n;

	if ( isnan( x ) ) {
		return x;
	}
	if ( x > MAXL10 ) {
		return PINF;
	}
	if ( x < MINL10 ) {
		return 0.0;
	}

	// Express 10^x = 10^g 2^n = 10^g 10^( n log10(2) ) = 10^( g + n log10(2) )
	px = floor( (LOG210*x) + 0.5 );
	n = px;
	x -= px * LG102A;
	x -= px * LG102B;

	// Rational approximation for exponential of the fractional part: 10^x = 1 + 2x P(x^2)/( Q(x^2) - P(x^2) )
	xx = x * x;
	px = x * polyvalP( xx );
	x = px / ( polyvalQ( xx ) - px );
	x = 1.0 + ldexp( x, 1 );

	// Multiply by power of 2:
	return ldexp( x, n );
}

// EXPORTS //

module.exports = exp10;
<|endoftext|>


<commit_before>'use strict';

/**
* Returns the complex conjugate of a complex number.
*
* @param {Complex} z - complex number
* @returns {number} complex conjugate
*
* @example
* var Complex128 = require( '@stdlib/types/complex/complex128' );
*
* var z = new Complex128( 5.0, 3.0 );
*
* var v = conj( z );
* // returns <Complex128>
*/
function conj( z ) {
	return new z.constructor( z.re, -z.im );
} // end FUNCTION conj()

// EXPORTS //

module.exports = conj;
<commit_msg>Fix return annotation<commit_after>'use strict';

/**
* Returns the complex conjugate of a complex number.
*
* @param {Complex} z - complex number
* @returns {Complex} complex conjugate
*
* @example
* var Complex128 = require( '@stdlib/types/complex/complex128' );
*
* var z = new Complex128( 5.0, 3.0 );
*
* var v = conj( z );
* // returns <Complex128>
*/
function conj( z ) {
	return new z.constructor( z.re, -z.im );
} // end FUNCTION conj()

// EXPORTS //

module.exports = conj;
<|endoftext|>


<commit_before>/**
 * Created by tungtouch on 2/5/15.
 */

/*
* Listen UDP from Device: 128.199.126.250
* */

var dgram = require("dgram");
var colors = require('colors');
var async = require('async');
var redis = require("redis");
var rClient = redis.createClient();
var client;
var d = new Date();

//var ports = [4000, 4001, 4002, 3333, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011];
var ports = [4444];
var r = 0;

rClient.on("error", function (err) {
    console.log("Error " + err);
});

var currentTime = d.getTime();
console.log("Current Time:", currentTime);
var ttl;
for(var i=0; i < ports.length; i++){

    client = dgram.createSocket('udp4', function(data){
        ttl = d.getTime() - currentTime;
        console.log("[1. Data Raw]: ".green, data);
        console.log("[2. JSON Data]: ".yellow, JSON.stringify(data));
        //console.log("[3. Decoder:]".blue, typeof data, data.toString('utf8'));
        console.log("-------------------------------------------------");
        console.log("Total request: ".blue, r++, ttl );

        rClient.hset("raw", "data"+r, data, redis.print);

    });

    console.log("Start listen port ",i,":",ports[i]);

    client.on("error", function (err) {
        console.log("Server error:\n".red + err.stack);
        client.close();
    });
    //
    client.on("message", function (msg, rinfo) {
        console.log("Server got: ".yellow + " IP: " +
        rinfo.address + " - Port:" + rinfo.port);

    });

    //client.on("listening", function () {
    //    var address = client.address();
    //    console.log("Server listening ".blue +
    //    address.address + ":" + address.port);
    //});

    client.bind(ports[i]);
}

<commit_msg>change port 3000<commit_after>/**
 * Created by tungtouch on 2/5/15.
 */

/*
* Listen UDP from Device: 128.199.126.250
* */

var dgram = require("dgram");
var colors = require('colors');
var async = require('async');
var redis = require("redis");
var rClient = redis.createClient();
var client;
var d = new Date();

//var ports = [4000, 4001, 4002, 3333, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011];
var ports = [4444];
var r = 0;

rClient.on("error", function (err) {
    console.log("Error " + err);
});

var currentTime = d.getTime();
console.log("Current Time:", currentTime);
var ttl;
for(var i=0; i < ports.length; i++){

    client = dgram.createSocket('udp4', function(data){
        var ttl = d.getDate();

        console.log("[1. Data Raw]: ".green, data);
        console.log("[2. JSON Data]: ".yellow, JSON.stringify(data));
        //console.log("[3. Decoder:]".blue, typeof data, data.toString('utf8'));
        console.log("-------------------------------------------------");
        console.log("Total request: ".blue, r++, ttl - currentTime);

        rClient.hset("raw", "data"+r, data, redis.print);

    });

    console.log("Start listen port ",i,":",ports[i]);

    client.on("error", function (err) {
        console.log("Server error:\n".red + err.stack);
        client.close();
    });
    //
    client.on("message", function (msg, rinfo) {
        console.log("Server got: ".yellow + " IP: " +
        rinfo.address + " - Port:" + rinfo.port);

    });

    //client.on("listening", function () {
    //    var address = client.address();
    //    console.log("Server listening ".blue +
    //    address.address + ":" + address.port);
    //});

    client.bind(ports[i]);
}

<|endoftext|>


<commit_before>var d = require ('dequeue');
var redis = require("redis");
var rClient = redis.createClient();
var dgram = require("dgram");

var FIFO = new d();

fetcher();

var udpserver = dgram.createSocket("udp4");
udpserver.on('error', function (err) {
    console.log("Error Server", err);
})
udpserver.on("message",
    function (msg, rinfo) {
        FIFO.push(msg.toString());
    }
);

udpserver.bind(4444);

var index =0;

function fetcher () {
    while (FIFO.length > 0)
    {
        var msg = FIFO.shift();
        index++;
        rClient.hset("raw", "data"+index, msg);
        console.log("Success: ", index);
    }
}<commit_msg>Update UDPefef<commit_after>var d = require ('dequeue');
var redis = require("redis");
var rClient = redis.createClient();
var dgram = require("dgram");

var FIFO = new d();
var index =0;

fetcher();

var udpserver = dgram.createSocket("udp4");
udpserver.on('error', function (err) {
    console.log("Error Server", err);
})
udpserver.on("message",
    function (msg, rinfo) {
        index++;
        FIFO.push(msg.toString());
        console.log("Success:", index);
    }
);

udpserver.bind(4444);

function fetcher () {
    while (FIFO.length > 0)
    {
        var msg = FIFO.shift();
        rClient.hset("raw", "data"+index, msg);
    }
}<|endoftext|>


<commit_before>var showterm=function(term){
	return ""+term.entry+"("+term.page+")"+" :
"+"藏文解釋 : "+term.tdefinition+"
 中文解釋 : "+term.cdefinition;
}

var showentry=function(term){
	var str = JSON.stringify(term,"","");
	return "
"+term.entry+"("+term.page+")
";
}

var doentrySearch=function(tofind){
	var arr=entrySearch(tofind);
	document.getElementById("display1").innerHTML=arr.map(showentry).join("
");
}

var showdetails=function(tofind){
	//var arr=entrySearch(tofind.replace(/\(\d+.\d+\)/,""));
	document.getElementById("display2").innerHTML=drawtable(tofind);
}

var drawtable = function(obj){
	//	var columnNumber = 10;
	return "<button onClick='edit()'>Edit</button>"+"

"+"Entry	"+"藏文解釋	"+"中文解釋	"+
			"

"+obj.entry+"	"+obj.tdefinition+"	"+
			obj.cdefinition+"

"+"
";
}

var edit=function(){
	var table=document.getElementById("details").innerHTML;
	var edittable="<button onClick='save_edit()'>Save</button>"+"
"+
					table.replace(/(.+?)<\/td>/g,"<textarea>$1</textarea>");
	document.getElementById("display2").innerHTML=edittable;
}

var save_edit=function(){
	var table=document.getElementById("edited_details").innerHTML;
	console.log(table);
	var savetable="<button onClick='edit()'>Save</button>"+"
"+
					table.replace(/<textarea>/g,"").replace(/<\/textarea>/g,"");
	document.getElementById("display2").innerHTML=savetable;
}	<commit_msg>add cancel (fix drawtable & save_edit)<commit_after>var showterm=function(term){
	return ""+term.entry+"("+term.page+")"+" :
"+"藏文解釋 : "+term.tdefinition+"
 中文解釋 : "+term.cdefinition;
}

var showentry=function(term){
	var str = JSON.stringify(term,"","");
	return "
"+term.entry+"("+term.page+")
";
}

var doentrySearch=function(tofind){
	var arr=entrySearch(tofind);
	document.getElementById("display1").innerHTML=arr.map(showentry).join("
");
}

var showdetails=function(tofind){
	//var arr=entrySearch(tofind.replace(/\(\d+.\d+\)/,""));
	document.getElementById("display2").innerHTML=drawtable(tofind);
}

var drawtable = function(obj){
	//	var columnNumber = 10;
	var table="<button onClick='edit()'>Edit</button>"+"

"+
			"Entry	"+"藏文解釋	"+
			"中文解釋	"+"

"+obj.entry+"	"+
			obj.tdefinition+"	"+obj.cdefinition+"

"+"
";
	localStorage.undo=table;
	return table;
}

var cancel=function(){
	document.getElementById("display2").innerHTML=localStorage.undo;
}

var edit=function(){
	var table=document.getElementById("details").innerHTML;
	var edittable="<button onClick='save_edit()'>Save</button>"+"<button onClick='cancel()'>Cancel</button>"
					+"
"+table.replace(//g,"");
	document.getElementById("display2").innerHTML=edittable;
}

var save_edit=function(){
	var table=document.getElementById("edited_details").innerHTML;

	var savetable="<button onClick='edit()'>Edit</button>"+"
"+
					table.replace(//g,"");
	localStorage.undo=savetable;
	document.getElementById("display2").innerHTML=savetable;
}	<|endoftext|>


<commit_before>define([
	"dojo/_base/kernel", // dojo.deprecated
	".",
	"./_Container",
	"./_FocusMixin",
	"dojo/_base/array", // dojo.forEach
	"dojo/_base/connect", // dojo.keys.END dojo.keys.HOME
	"dojo/_base/declare", // dojo.declare
	"dojo/_base/event", // dojo.stopEvent
	"dojo/_base/html", // dojo.attr
	"dojo/_base/lang" // dojo.hitch
], function(dojo, dijit){

	// module:
	//		dijit/_KeyNavContainer
	// summary:
	//		A _Container with keyboard navigation of its children.

	dojo.declare("dijit._KeyNavContainer", [dijit._Container, dijit._FocusMixin], {

		// summary:
		//		A _Container with keyboard navigation of its children.
		// description:
		//		To use this mixin, call connectKeyNavHandlers() in
		//		postCreate().
		//		It provides normalized keyboard and focusing code for Container
		//		widgets.

/*=====
		// focusedChild: [protected] Widget
		//		The currently focused child widget, or null if there isn't one
		focusedChild: null,
=====*/

		// tabIndex: Integer
		//		Tab index of the container; same as HTML tabIndex attribute.
		//		Note then when user tabs into the container, focus is immediately
		//		moved to the first item in the container.
		tabIndex: "0",

		connectKeyNavHandlers: function(/*dojo.keys[]*/ prevKeyCodes, /*dojo.keys[]*/ nextKeyCodes){
			// summary:
			//		Call in postCreate() to attach the keyboard handlers
			//		to the container.
			// preKeyCodes: dojo.keys[]
			//		Key codes for navigating to the previous child.
			// nextKeyCodes: dojo.keys[]
			//		Key codes for navigating to the next child.
			// tags:
			//		protected

			// TODO: call this automatically from my own postCreate()

			var keyCodes = (this._keyNavCodes = {});
			var prev = dojo.hitch(this, "focusPrev");
			var next = dojo.hitch(this, "focusNext");
			dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
			dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
			keyCodes[dojo.keys.HOME] = dojo.hitch(this, "focusFirstChild");
			keyCodes[dojo.keys.END] = dojo.hitch(this, "focusLastChild");
			this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
			this.connect(this.domNode, "onfocus", "_onContainerFocus");
		},

		startupKeyNavChildren: function(){
			dojo.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
		},

		startup: function(){
			this.inherited(arguments);
			dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
		},

		addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
			this.inherited(arguments);
			this._startupChild(widget);
		},

		focus: function(){
			// summary:
			//		Default focus() implementation: focus the first child.
			this.focusFirstChild();
		},

		focusFirstChild: function(){
			// summary:
			//		Focus the first focusable child in the container.
			// tags:
			//		protected
			this.focusChild(this._getFirstFocusableChild());
		},

		focusLastChild: function(){
			// summary:
			//		Focus the last focusable child in the container.
			// tags:
			//		protected
			this.focusChild(this._getLastFocusableChild());
		},

		focusNext: function(){
			// summary:
			//		Focus the next widget
			// tags:
			//		protected
			this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
		},

		focusPrev: function(){
			// summary:
			//		Focus the last focusable node in the previous widget
			//		(ex: go to the ComboButton icon section rather than button section)
			// tags:
			//		protected
			this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
		},

		focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
			// summary:
			//		Focus specified child widget.
			// widget:
			//		Reference to container's child widget
			// last:
			//		If true and if widget has multiple focusable nodes, focus the
			//		last one instead of the first one
			// tags:
			//		protected

			if(!widget){ return; }

			if(this.focusedChild && widget !== this.focusedChild){
				this._onChildBlur(this.focusedChild);	// used by _MenuBase
			}
			widget.set("tabIndex", this.tabIndex);	// for IE focus outline to appear, must set tabIndex before focs
			widget.focus(last ? "end" : "start");
			this._set("focusedChild", widget);
		},

		_startupChild: function(/*dijit._Widget*/ widget){
			// summary:
			//		Setup for each child widget
			// description:
			//		Sets tabIndex=-1 on each child, so that the tab key will
			//		leave the container rather than visiting each child.
			// tags:
			//		private

			widget.set("tabIndex", "-1");

			this.connect(widget, "_onFocus", function(){
				// Set valid tabIndex so tabbing away from widget goes to right place, see #10272
				widget.set("tabIndex", this.tabIndex);
			});
			this.connect(widget, "_onBlur", function(){
				widget.set("tabIndex", "-1");
			});
		},

		_onContainerFocus: function(evt){
			// summary:
			//		Handler for when the container gets focus
			// description:
			//		Initially the container itself has a tabIndex, but when it gets
			//		focus, switch focus to first child...
			// tags:
			//		private

			// Note that we can't use _onFocus() because switching focus from the
			// _onFocus() handler confuses the focus.js code
			// (because it causes _onFocusNode() to be called recursively)
			// Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.

			// Ignore spurious focus events:
			//	1. focus on a child widget bubbles on FF
			//	2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
			if(evt.target !== this.domNode || this.focusedChild){ return; }

			this.focusFirstChild();

			// and then set the container's tabIndex to -1,
			// (don't remove as that breaks Safari 4)
			// so that tab or shift-tab will go to the fields after/before
			// the container, rather than the container itself
			dojo.attr(this.domNode, "tabIndex", "-1");
		},

		_onBlur: function(evt){
			// When focus is moved away the container, and its descendant (popup) widgets,
			// then restore the container's tabIndex so that user can tab to it again.
			// Note that using _onBlur() so that this doesn't happen when focus is shifted
			// to one of my child widgets (typically a popup)
			if(this.tabIndex){
				dojo.attr(this.domNode, "tabIndex", this.tabIndex);
			}
			this.focusedChild = null;
			this.inherited(arguments);
		},

		_onContainerKeypress: function(evt){
			// summary:
			//		When a key is pressed, if it's an arrow key etc. then
			//		it's handled here.
			// tags:
			//		private
			if(evt.ctrlKey || evt.altKey){ return; }
			var func = this._keyNavCodes[evt.charOrCode];
			if(func){
				func();
				dojo.stopEvent(evt);
			}
		},

		_onChildBlur: function(/*dijit._Widget*/ widget){
			// summary:
			//		Called when focus leaves a child widget to go
			//		to a sibling widget.
			//		Used by MenuBase.js (TODO: move code there)
			// tags:
			//		protected
		},

		_getFirstFocusableChild: function(){
			// summary:
			//		Returns first child that can be focused
			return this._getNextFocusableChild(null, 1);	// dijit._Widget
		},

		_getLastFocusableChild: function(){
			// summary:
			//		Returns last child that can be focused
			return this._getNextFocusableChild(null, -1);	// dijit._Widget
		},

		_getNextFocusableChild: function(child, dir){
			// summary:
			//		Returns the next or previous focusable child, compared
			//		to "child"
			// child: Widget
			//		The current widget
			// dir: Integer
			//		* 1 = after
			//		* -1 = before
			if(child){
				child = this._getSiblingOfChild(child, dir);
			}
			var children = this.getChildren();
			for(var i=0; i < children.length; i++){
				if(!child){
					child = children[(dir>0) ? 0 : (children.length-1)];
				}
				if(child.isFocusable()){
					return child;	// dijit._Widget
				}
				child = this._getSiblingOfChild(child, dir);
			}
			// no focusable child found
			return null;	// dijit._Widget
		}
	});

	return dijit._KeyNavContainer;
});
<commit_msg>Fix inheritance chain so that _WidgetBase is (prototypically) inherited by widgets, rather than being a mixin.   Thanks to Ben for tracking all this down and the patch.   Fixes #13372 !strict.<commit_after>define([
	"dojo/_base/kernel", // dojo.deprecated
	".",
	"./_Container",
	"./_FocusMixin",
	"dojo/_base/array", // dojo.forEach
	"dojo/_base/connect", // dojo.keys.END dojo.keys.HOME
	"dojo/_base/declare", // dojo.declare
	"dojo/_base/event", // dojo.stopEvent
	"dojo/_base/html", // dojo.attr
	"dojo/_base/lang" // dojo.hitch
], function(dojo, dijit){

	// module:
	//		dijit/_KeyNavContainer
	// summary:
	//		A _Container with keyboard navigation of its children.

	dojo.declare("dijit._KeyNavContainer", [dijit._FocusMixin, dijit._Container], {

		// summary:
		//		A _Container with keyboard navigation of its children.
		// description:
		//		To use this mixin, call connectKeyNavHandlers() in
		//		postCreate().
		//		It provides normalized keyboard and focusing code for Container
		//		widgets.

/*=====
		// focusedChild: [protected] Widget
		//		The currently focused child widget, or null if there isn't one
		focusedChild: null,
=====*/

		// tabIndex: Integer
		//		Tab index of the container; same as HTML tabIndex attribute.
		//		Note then when user tabs into the container, focus is immediately
		//		moved to the first item in the container.
		tabIndex: "0",

		connectKeyNavHandlers: function(/*dojo.keys[]*/ prevKeyCodes, /*dojo.keys[]*/ nextKeyCodes){
			// summary:
			//		Call in postCreate() to attach the keyboard handlers
			//		to the container.
			// preKeyCodes: dojo.keys[]
			//		Key codes for navigating to the previous child.
			// nextKeyCodes: dojo.keys[]
			//		Key codes for navigating to the next child.
			// tags:
			//		protected

			// TODO: call this automatically from my own postCreate()

			var keyCodes = (this._keyNavCodes = {});
			var prev = dojo.hitch(this, "focusPrev");
			var next = dojo.hitch(this, "focusNext");
			dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
			dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
			keyCodes[dojo.keys.HOME] = dojo.hitch(this, "focusFirstChild");
			keyCodes[dojo.keys.END] = dojo.hitch(this, "focusLastChild");
			this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
			this.connect(this.domNode, "onfocus", "_onContainerFocus");
		},

		startupKeyNavChildren: function(){
			dojo.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
		},

		startup: function(){
			this.inherited(arguments);
			dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
		},

		addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
			this.inherited(arguments);
			this._startupChild(widget);
		},

		focus: function(){
			// summary:
			//		Default focus() implementation: focus the first child.
			this.focusFirstChild();
		},

		focusFirstChild: function(){
			// summary:
			//		Focus the first focusable child in the container.
			// tags:
			//		protected
			this.focusChild(this._getFirstFocusableChild());
		},

		focusLastChild: function(){
			// summary:
			//		Focus the last focusable child in the container.
			// tags:
			//		protected
			this.focusChild(this._getLastFocusableChild());
		},

		focusNext: function(){
			// summary:
			//		Focus the next widget
			// tags:
			//		protected
			this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
		},

		focusPrev: function(){
			// summary:
			//		Focus the last focusable node in the previous widget
			//		(ex: go to the ComboButton icon section rather than button section)
			// tags:
			//		protected
			this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
		},

		focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
			// summary:
			//		Focus specified child widget.
			// widget:
			//		Reference to container's child widget
			// last:
			//		If true and if widget has multiple focusable nodes, focus the
			//		last one instead of the first one
			// tags:
			//		protected

			if(!widget){ return; }

			if(this.focusedChild && widget !== this.focusedChild){
				this._onChildBlur(this.focusedChild);	// used by _MenuBase
			}
			widget.set("tabIndex", this.tabIndex);	// for IE focus outline to appear, must set tabIndex before focs
			widget.focus(last ? "end" : "start");
			this._set("focusedChild", widget);
		},

		_startupChild: function(/*dijit._Widget*/ widget){
			// summary:
			//		Setup for each child widget
			// description:
			//		Sets tabIndex=-1 on each child, so that the tab key will
			//		leave the container rather than visiting each child.
			// tags:
			//		private

			widget.set("tabIndex", "-1");

			this.connect(widget, "_onFocus", function(){
				// Set valid tabIndex so tabbing away from widget goes to right place, see #10272
				widget.set("tabIndex", this.tabIndex);
			});
			this.connect(widget, "_onBlur", function(){
				widget.set("tabIndex", "-1");
			});
		},

		_onContainerFocus: function(evt){
			// summary:
			//		Handler for when the container gets focus
			// description:
			//		Initially the container itself has a tabIndex, but when it gets
			//		focus, switch focus to first child...
			// tags:
			//		private

			// Note that we can't use _onFocus() because switching focus from the
			// _onFocus() handler confuses the focus.js code
			// (because it causes _onFocusNode() to be called recursively)
			// Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.

			// Ignore spurious focus events:
			//	1. focus on a child widget bubbles on FF
			//	2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
			if(evt.target !== this.domNode || this.focusedChild){ return; }

			this.focusFirstChild();

			// and then set the container's tabIndex to -1,
			// (don't remove as that breaks Safari 4)
			// so that tab or shift-tab will go to the fields after/before
			// the container, rather than the container itself
			dojo.attr(this.domNode, "tabIndex", "-1");
		},

		_onBlur: function(evt){
			// When focus is moved away the container, and its descendant (popup) widgets,
			// then restore the container's tabIndex so that user can tab to it again.
			// Note that using _onBlur() so that this doesn't happen when focus is shifted
			// to one of my child widgets (typically a popup)
			if(this.tabIndex){
				dojo.attr(this.domNode, "tabIndex", this.tabIndex);
			}
			this.focusedChild = null;
			this.inherited(arguments);
		},

		_onContainerKeypress: function(evt){
			// summary:
			//		When a key is pressed, if it's an arrow key etc. then
			//		it's handled here.
			// tags:
			//		private
			if(evt.ctrlKey || evt.altKey){ return; }
			var func = this._keyNavCodes[evt.charOrCode];
			if(func){
				func();
				dojo.stopEvent(evt);
			}
		},

		_onChildBlur: function(/*dijit._Widget*/ widget){
			// summary:
			//		Called when focus leaves a child widget to go
			//		to a sibling widget.
			//		Used by MenuBase.js (TODO: move code there)
			// tags:
			//		protected
		},

		_getFirstFocusableChild: function(){
			// summary:
			//		Returns first child that can be focused
			return this._getNextFocusableChild(null, 1);	// dijit._Widget
		},

		_getLastFocusableChild: function(){
			// summary:
			//		Returns last child that can be focused
			return this._getNextFocusableChild(null, -1);	// dijit._Widget
		},

		_getNextFocusableChild: function(child, dir){
			// summary:
			//		Returns the next or previous focusable child, compared
			//		to "child"
			// child: Widget
			//		The current widget
			// dir: Integer
			//		* 1 = after
			//		* -1 = before
			if(child){
				child = this._getSiblingOfChild(child, dir);
			}
			var children = this.getChildren();
			for(var i=0; i < children.length; i++){
				if(!child){
					child = children[(dir>0) ? 0 : (children.length-1)];
				}
				if(child.isFocusable()){
					return child;	// dijit._Widget
				}
				child = this._getSiblingOfChild(child, dir);
			}
			// no focusable child found
			return null;	// dijit._Widget
		}
	});

	return dijit._KeyNavContainer;
});
<|endoftext|>