<commit_before>'use strict';

import $ from 'jquery';
import { Keyboard } from './foundation.util.keyboard';
import { GetYoDigits, ignoreMousedisappear } from './foundation.core.utils';
import { Positionable } from './foundation.positionable';

import { Triggers } from './foundation.util.triggers';

/**
 * Dropdown module.
 * @module foundation.dropdown
 * @requires foundation.util.keyboard
 * @requires foundation.util.box
 * @requires foundation.util.triggers
 */
class Dropdown extends Positionable {
  /**
   * Creates a new instance of a dropdown.
   * @class
   * @name Dropdown
   * @param {jQuery} element - jQuery object to make into a dropdown.
   *        Object should be of the dropdown panel, rather than its anchor.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  _setup(element, options) {
    this.$element = element;
    this.options = $.extend({}, Dropdown.defaults, this.$element.data(), options);
    this.className = 'Dropdown'; // ie9 back compat

    // Triggers init is idempotent, just need to make sure it is initialized
    Triggers.init($);

    this._init();

    Keyboard.register('Dropdown', {
      'ENTER': 'toggle',
      'SPACE': 'toggle',
      'ESCAPE': 'close'
    });
  }

  /**
   * Initializes the plugin by setting/checking options and attributes, adding helper variables, and saving the anchor.
   * @function
   * @private
   */
  _init() {
    var $id = this.$element.attr('id');

    this.$anchors = $(`[data-toggle="${$id}"]`).length ? $(`[data-toggle="${$id}"]`) : $(`[data-open="${$id}"]`);
    this.$anchors.attr({
      'aria-controls': $id,
      'data-is-focus': false,
      'data-yeti-box': $id,
      'aria-haspopup': true,
      'aria-expanded': false
    });

    this._setCurrentAnchor(this.$anchors.first());

    if(this.options.parentClass){
      this.$parent = this.$element.parents('.' + this.options.parentClass);
    }else{
      this.$parent = null;
    }

    // Do not change the `labelledby` if it is defined
    var labelledby = this.$element.attr('aria-labelledby')
      || this.$currentAnchor.attr('id')
      || GetYoDigits(6, 'dd-anchor');

    this.$element.attr({
      'aria-hidden': 'true',
      'data-yeti-box': $id,
      'data-resize': $id,
      'aria-labelledby': labelledby
    });

    super._init();
    this._events();
  }

  _getDefaultPosition() {
    // handle legacy classnames
    var position = this.$element[0].className.match(/(top|left|right|bottom)/g);
    if(position) {
      return position[0];
    } else {
      return 'bottom'
    }
  }

  _getDefaultAlignment() {
    // handle legacy float approach
    var horizontalPosition = /float-(\S+)/.exec(this.$currentAnchor.attr('class'));
    if(horizontalPosition) {
      return horizontalPosition[1];
    }

    return super._getDefaultAlignment();
  }

  /**
   * Sets the position and orientation of the dropdown pane, checks for collisions if allow-overlap is not true.
   * Recursively calls itself if a collision is detected, with a new position class.
   * @function
   * @private
   */
  _setPosition() {
    this.$element.removeClass(`has-position-${this.position} has-alignment-${this.alignment}`);
    super._setPosition(this.$currentAnchor, this.$element, this.$parent);
    this.$element.addClass(`has-position-${this.position} has-alignment-${this.alignment}`);
  }

  /**
   * Make it a current anchor.
   * Current anchor as the reference for the position of Dropdown panes.
   * @param {HTML} el - DOM element of the anchor.
   * @function
   * @private
   */
  _setCurrentAnchor(el) {
    this.$currentAnchor = $(el);
  }

  /**
   * Adds event listeners to the element utilizing the triggers utility library.
   * @function
   * @private
   */
  _events() {
    var _this = this;
    this.$element.on({
      'open.zf.trigger': this.open.bind(this),
      'close.zf.trigger': this.close.bind(this),
      'toggle.zf.trigger': this.toggle.bind(this),
      'resizeme.zf.trigger': this._setPosition.bind(this)
    });

    this.$anchors.off('click.zf.trigger')
      .on('click.zf.trigger', function() { _this._setCurrentAnchor(this); });

    if(this.options.hover){
      this.$anchors.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
      .on('mouseenter.zf.dropdown', function(){
        _this._setCurrentAnchor(this);

        var bodyData = $('body').data();
        if(typeof(bodyData.whatinput) === 'undefined' || bodyData.whatinput === 'mouse') {
          clearTimeout(_this.timeout);
          _this.timeout = setTimeout(function(){
            _this.open();
            _this.$anchors.data('hover', true);
          }, _this.options.hoverDelay);
        }
      }).on('mouseleave.zf.dropdown', ignoreMousedisappear(function(){
        clearTimeout(_this.timeout);
        _this.timeout = setTimeout(function(){
          _this.close();
          _this.$anchors.data('hover', false);
        }, _this.options.hoverDelay);
      }));
      if(this.options.hoverPane){
        this.$element.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
            .on('mouseenter.zf.dropdown', function(){
              clearTimeout(_this.timeout);
            }).on('mouseleave.zf.dropdown', ignoreMousedisappear(function(){
              clearTimeout(_this.timeout);
              _this.timeout = setTimeout(function(){
                _this.close();
                _this.$anchors.data('hover', false);
              }, _this.options.hoverDelay);
            }));
      }
    }
    this.$anchors.add(this.$element).on('keydown.zf.dropdown', function(e) {

      var $target = $(this),
        visibleFocusableElements = Keyboard.findFocusable(_this.$element);

      Keyboard.handleKey(e, 'Dropdown', {
        open: function() {
          if ($target.is(_this.$anchors) && !$target.is('input, textarea')) {
            _this.open();
            _this.$element.attr('tabindex', -1).focus();
            e.preventDefault();
          }
        },
        close: function() {
          _this.close();
          _this.$anchors.focus();
        }
      });
    });
  }

  /**
   * Adds an event handler to the body to close any dropdowns on a click.
   * @function
   * @private
   */
  _addBodyHandler() {
     var $body = $(document.body).not(this.$element),
         _this = this;
     $body.off('click.zf.dropdown')
          .on('click.zf.dropdown', function(e){
            if(_this.$anchors.is(e.target) || _this.$anchors.find(e.target).length) {
              return;
            }
            if(_this.$element.is(e.target) || _this.$element.find(e.target).length) {
              return;
            }
            _this.close();
            $body.off('click.zf.dropdown');
          });
  }

  /**
   * Opens the dropdown pane, and fires a bubbling event to close other dropdowns.
   * @function
   * @fires Dropdown#closeme
   * @fires Dropdown#show
   */
  open() {
    // var _this = this;
    /**
     * Fires to close other open dropdowns, typically when dropdown is opening
     * @event Dropdown#closeme
     */
    this.$element.trigger('closeme.zf.dropdown', this.$element.attr('id'));
    this.$anchors.addClass('hover')
        .attr({'aria-expanded': true});
    // this.$element/*.show()*/;

    this.$element.addClass('is-opening');
    this._setPosition();
    this.$element.removeClass('is-opening').addClass('is-open')
        .attr({'aria-hidden': false});

    if(this.options.autoFocus){
      var $focusable = Keyboard.findFocusable(this.$element);
      if($focusable.length){
        $focusable.eq(0).focus();
      }
    }

    if(this.options.closeOnClick){ this._addBodyHandler(); }

    if (this.options.trapFocus) {
      Keyboard.trapFocus(this.$element);
    }

    /**
     * Fires once the dropdown is visible.
     * @event Dropdown#show
     */
    this.$element.trigger('show.zf.dropdown', [this.$element]);
  }

  /**
   * Closes the open dropdown pane.
   * @function
   * @fires Dropdown#hide
   */
  close() {
    if(!this.$element.hasClass('is-open')){
      return false;
    }
    this.$element.removeClass('is-open')
        .attr({'aria-hidden': true});

    this.$anchors.removeClass('hover')
        .attr('aria-expanded', false);

    /**
     * Fires once the dropdown is no longer visible.
     * @event Dropdown#hide
     */
    this.$element.trigger('hide.zf.dropdown', [this.$element]);

    if (this.options.trapFocus) {
      Keyboard.releaseFocus(this.$element);
    }
  }

  /**
   * Toggles the dropdown pane's visibility.
   * @function
   */
  toggle() {
    if(this.$element.hasClass('is-open')){
      if(this.$anchors.data('hover')) return;
      this.close();
    }else{
      this.open();
    }
  }

  /**
   * Destroys the dropdown.
   * @function
   */
  _destroy() {
    this.$element.off('.zf.trigger').hide();
    this.$anchors.off('.zf.dropdown');
    $(document.body).off('click.zf.dropdown');

  }
}

Dropdown.defaults = {
  /**
   * Class that designates bounding container of Dropdown (default: window)
   * @option
   * @type {?string}
   * @default null
   */
  parentClass: null,
  /**
   * Amount of time to delay opening a submenu on hover event.
   * @option
   * @type {number}
   * @default 250
   */
  hoverDelay: 250,
  /**
   * Allow submenus to open on hover events
   * @option
   * @type {boolean}
   * @default false
   */
  hover: false,
  /**
   * Don't close dropdown when hovering over dropdown pane
   * @option
   * @type {boolean}
   * @default false
   */
  hoverPane: false,
  /**
   * Number of pixels between the dropdown pane and the triggering element on open.
   * @option
   * @type {number}
   * @default 0
   */
  vOffset: 0,
  /**
   * Number of pixels between the dropdown pane and the triggering element on open.
   * @option
   * @type {number}
   * @default 0
   */
  hOffset: 0,
  /**
   * Position of dropdown. Can be left, right, bottom, top, or auto.
   * @option
   * @type {string}
   * @default 'auto'
   */
  position: 'auto',
  /**
   * Alignment of dropdown relative to anchor. Can be left, right, bottom, top, center, or auto.
   * @option
   * @type {string}
   * @default 'auto'
   */
  alignment: 'auto',
  /**
   * Allow overlap of container/window. If false, dropdown will first try to position as defined by data-position and data-alignment, but reposition if it would cause an overflow.
   * @option
   * @type {boolean}
   * @default false
   */
  allowOverlap: false,
  /**
   * Allow overlap of only the bottom of the container. This is the most common
   * behavior for dropdowns, allowing the dropdown to extend the bottom of the
   * screen but not otherwise influence or break out of the container.
   * @option
   * @type {boolean}
   * @default true
   */
  allowBottomOverlap: true,
  /**
   * Allow the plugin to trap focus to the dropdown pane if opened with keyboard commands.
   * @option
   * @type {boolean}
   * @default false
   */
  trapFocus: false,
  /**
   * Allow the plugin to set focus to the first focusable element within the pane, regardless of method of opening.
   * @option
   * @type {boolean}
   * @default false
   */
  autoFocus: false,
  /**
   * Allows a click on the body to close the dropdown.
   * @option
   * @type {boolean}
   * @default false
   */
  closeOnClick: false
};

export {Dropdown};
<commit_msg>Use pull request #11573 from ncoden/fix/dropdown-aria-missing-id-11572 for v6.5.1<commit_after>'use strict';

import $ from 'jquery';
import { Keyboard } from './foundation.util.keyboard';
import { GetYoDigits, ignoreMousedisappear } from './foundation.core.utils';
import { Positionable } from './foundation.positionable';

import { Triggers } from './foundation.util.triggers';

/**
 * Dropdown module.
 * @module foundation.dropdown
 * @requires foundation.util.keyboard
 * @requires foundation.util.box
 * @requires foundation.util.triggers
 */
class Dropdown extends Positionable {
  /**
   * Creates a new instance of a dropdown.
   * @class
   * @name Dropdown
   * @param {jQuery} element - jQuery object to make into a dropdown.
   *        Object should be of the dropdown panel, rather than its anchor.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  _setup(element, options) {
    this.$element = element;
    this.options = $.extend({}, Dropdown.defaults, this.$element.data(), options);
    this.className = 'Dropdown'; // ie9 back compat

    // Triggers init is idempotent, just need to make sure it is initialized
    Triggers.init($);

    this._init();

    Keyboard.register('Dropdown', {
      'ENTER': 'toggle',
      'SPACE': 'toggle',
      'ESCAPE': 'close'
    });
  }

  /**
   * Initializes the plugin by setting/checking options and attributes, adding helper variables, and saving the anchor.
   * @function
   * @private
   */
  _init() {
    var $id = this.$element.attr('id');

    this.$anchors = $(`[data-toggle="${$id}"]`).length ? $(`[data-toggle="${$id}"]`) : $(`[data-open="${$id}"]`);
    this.$anchors.attr({
      'aria-controls': $id,
      'data-is-focus': false,
      'data-yeti-box': $id,
      'aria-haspopup': true,
      'aria-expanded': false
    });

    this._setCurrentAnchor(this.$anchors.first());

    if(this.options.parentClass){
      this.$parent = this.$element.parents('.' + this.options.parentClass);
    }else{
      this.$parent = null;
    }

    // Set [aria-labelledby] on the Dropdown if it is not set
    if (typeof this.$element.attr('aria-labelledby') === 'undefined') {
      // Get the anchor ID or create one
      if (typeof this.$currentAnchor.attr('id') === 'undefined') {
        this.$currentAnchor.attr('id', GetYoDigits(6, 'dd-anchor'));
      };

      this.$element.attr('aria-labelledby', this.$currentAnchor.attr('id'));
    }

    this.$element.attr({
      'aria-hidden': 'true',
      'data-yeti-box': $id,
      'data-resize': $id,
    });

    super._init();
    this._events();
  }

  _getDefaultPosition() {
    // handle legacy classnames
    var position = this.$element[0].className.match(/(top|left|right|bottom)/g);
    if(position) {
      return position[0];
    } else {
      return 'bottom'
    }
  }

  _getDefaultAlignment() {
    // handle legacy float approach
    var horizontalPosition = /float-(\S+)/.exec(this.$currentAnchor.attr('class'));
    if(horizontalPosition) {
      return horizontalPosition[1];
    }

    return super._getDefaultAlignment();
  }

  /**
   * Sets the position and orientation of the dropdown pane, checks for collisions if allow-overlap is not true.
   * Recursively calls itself if a collision is detected, with a new position class.
   * @function
   * @private
   */
  _setPosition() {
    this.$element.removeClass(`has-position-${this.position} has-alignment-${this.alignment}`);
    super._setPosition(this.$currentAnchor, this.$element, this.$parent);
    this.$element.addClass(`has-position-${this.position} has-alignment-${this.alignment}`);
  }

  /**
   * Make it a current anchor.
   * Current anchor as the reference for the position of Dropdown panes.
   * @param {HTML} el - DOM element of the anchor.
   * @function
   * @private
   */
  _setCurrentAnchor(el) {
    this.$currentAnchor = $(el);
  }

  /**
   * Adds event listeners to the element utilizing the triggers utility library.
   * @function
   * @private
   */
  _events() {
    var _this = this;
    this.$element.on({
      'open.zf.trigger': this.open.bind(this),
      'close.zf.trigger': this.close.bind(this),
      'toggle.zf.trigger': this.toggle.bind(this),
      'resizeme.zf.trigger': this._setPosition.bind(this)
    });

    this.$anchors.off('click.zf.trigger')
      .on('click.zf.trigger', function() { _this._setCurrentAnchor(this); });

    if(this.options.hover){
      this.$anchors.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
      .on('mouseenter.zf.dropdown', function(){
        _this._setCurrentAnchor(this);

        var bodyData = $('body').data();
        if(typeof(bodyData.whatinput) === 'undefined' || bodyData.whatinput === 'mouse') {
          clearTimeout(_this.timeout);
          _this.timeout = setTimeout(function(){
            _this.open();
            _this.$anchors.data('hover', true);
          }, _this.options.hoverDelay);
        }
      }).on('mouseleave.zf.dropdown', ignoreMousedisappear(function(){
        clearTimeout(_this.timeout);
        _this.timeout = setTimeout(function(){
          _this.close();
          _this.$anchors.data('hover', false);
        }, _this.options.hoverDelay);
      }));
      if(this.options.hoverPane){
        this.$element.off('mouseenter.zf.dropdown mouseleave.zf.dropdown')
            .on('mouseenter.zf.dropdown', function(){
              clearTimeout(_this.timeout);
            }).on('mouseleave.zf.dropdown', ignoreMousedisappear(function(){
              clearTimeout(_this.timeout);
              _this.timeout = setTimeout(function(){
                _this.close();
                _this.$anchors.data('hover', false);
              }, _this.options.hoverDelay);
            }));
      }
    }
    this.$anchors.add(this.$element).on('keydown.zf.dropdown', function(e) {

      var $target = $(this),
        visibleFocusableElements = Keyboard.findFocusable(_this.$element);

      Keyboard.handleKey(e, 'Dropdown', {
        open: function() {
          if ($target.is(_this.$anchors) && !$target.is('input, textarea')) {
            _this.open();
            _this.$element.attr('tabindex', -1).focus();
            e.preventDefault();
          }
        },
        close: function() {
          _this.close();
          _this.$anchors.focus();
        }
      });
    });
  }

  /**
   * Adds an event handler to the body to close any dropdowns on a click.
   * @function
   * @private
   */
  _addBodyHandler() {
     var $body = $(document.body).not(this.$element),
         _this = this;
     $body.off('click.zf.dropdown')
          .on('click.zf.dropdown', function(e){
            if(_this.$anchors.is(e.target) || _this.$anchors.find(e.target).length) {
              return;
            }
            if(_this.$element.is(e.target) || _this.$element.find(e.target).length) {
              return;
            }
            _this.close();
            $body.off('click.zf.dropdown');
          });
  }

  /**
   * Opens the dropdown pane, and fires a bubbling event to close other dropdowns.
   * @function
   * @fires Dropdown#closeme
   * @fires Dropdown#show
   */
  open() {
    // var _this = this;
    /**
     * Fires to close other open dropdowns, typically when dropdown is opening
     * @event Dropdown#closeme
     */
    this.$element.trigger('closeme.zf.dropdown', this.$element.attr('id'));
    this.$anchors.addClass('hover')
        .attr({'aria-expanded': true});
    // this.$element/*.show()*/;

    this.$element.addClass('is-opening');
    this._setPosition();
    this.$element.removeClass('is-opening').addClass('is-open')
        .attr({'aria-hidden': false});

    if(this.options.autoFocus){
      var $focusable = Keyboard.findFocusable(this.$element);
      if($focusable.length){
        $focusable.eq(0).focus();
      }
    }

    if(this.options.closeOnClick){ this._addBodyHandler(); }

    if (this.options.trapFocus) {
      Keyboard.trapFocus(this.$element);
    }

    /**
     * Fires once the dropdown is visible.
     * @event Dropdown#show
     */
    this.$element.trigger('show.zf.dropdown', [this.$element]);
  }

  /**
   * Closes the open dropdown pane.
   * @function
   * @fires Dropdown#hide
   */
  close() {
    if(!this.$element.hasClass('is-open')){
      return false;
    }
    this.$element.removeClass('is-open')
        .attr({'aria-hidden': true});

    this.$anchors.removeClass('hover')
        .attr('aria-expanded', false);

    /**
     * Fires once the dropdown is no longer visible.
     * @event Dropdown#hide
     */
    this.$element.trigger('hide.zf.dropdown', [this.$element]);

    if (this.options.trapFocus) {
      Keyboard.releaseFocus(this.$element);
    }
  }

  /**
   * Toggles the dropdown pane's visibility.
   * @function
   */
  toggle() {
    if(this.$element.hasClass('is-open')){
      if(this.$anchors.data('hover')) return;
      this.close();
    }else{
      this.open();
    }
  }

  /**
   * Destroys the dropdown.
   * @function
   */
  _destroy() {
    this.$element.off('.zf.trigger').hide();
    this.$anchors.off('.zf.dropdown');
    $(document.body).off('click.zf.dropdown');

  }
}

Dropdown.defaults = {
  /**
   * Class that designates bounding container of Dropdown (default: window)
   * @option
   * @type {?string}
   * @default null
   */
  parentClass: null,
  /**
   * Amount of time to delay opening a submenu on hover event.
   * @option
   * @type {number}
   * @default 250
   */
  hoverDelay: 250,
  /**
   * Allow submenus to open on hover events
   * @option
   * @type {boolean}
   * @default false
   */
  hover: false,
  /**
   * Don't close dropdown when hovering over dropdown pane
   * @option
   * @type {boolean}
   * @default false
   */
  hoverPane: false,
  /**
   * Number of pixels between the dropdown pane and the triggering element on open.
   * @option
   * @type {number}
   * @default 0
   */
  vOffset: 0,
  /**
   * Number of pixels between the dropdown pane and the triggering element on open.
   * @option
   * @type {number}
   * @default 0
   */
  hOffset: 0,
  /**
   * Position of dropdown. Can be left, right, bottom, top, or auto.
   * @option
   * @type {string}
   * @default 'auto'
   */
  position: 'auto',
  /**
   * Alignment of dropdown relative to anchor. Can be left, right, bottom, top, center, or auto.
   * @option
   * @type {string}
   * @default 'auto'
   */
  alignment: 'auto',
  /**
   * Allow overlap of container/window. If false, dropdown will first try to position as defined by data-position and data-alignment, but reposition if it would cause an overflow.
   * @option
   * @type {boolean}
   * @default false
   */
  allowOverlap: false,
  /**
   * Allow overlap of only the bottom of the container. This is the most common
   * behavior for dropdowns, allowing the dropdown to extend the bottom of the
   * screen but not otherwise influence or break out of the container.
   * @option
   * @type {boolean}
   * @default true
   */
  allowBottomOverlap: true,
  /**
   * Allow the plugin to trap focus to the dropdown pane if opened with keyboard commands.
   * @option
   * @type {boolean}
   * @default false
   */
  trapFocus: false,
  /**
   * Allow the plugin to set focus to the first focusable element within the pane, regardless of method of opening.
   * @option
   * @type {boolean}
   * @default false
   */
  autoFocus: false,
  /**
   * Allows a click on the body to close the dropdown.
   * @option
   * @type {boolean}
   * @default false
   */
  closeOnClick: false
};

export {Dropdown};
<|endoftext|>


<commit_before>'use strict';
const APP_ID = process.env.APP_ID;
const WORD_TYPES = {
    'n': 'noun',
    'v': 'verb',
    'adv': 'adverb',
    'adj': 'adjective',
    'pron': 'pronoun',
    'interj': 'interjection',
    'conj': 'conjunction',
    'prep': 'preposition'
};

function makeResult(term, item) {
    let type = (WORD_TYPES[item.pos]) ? WORD_TYPES[item.pos] + ' ' : '';
    return term + type + ' ' + item.etymology;
}

module.exports = function(etty) {
    return {
        'LaunchRequest': function () {
            this.attributes.speechOutput = this.t('LAUNCH_MESSAGE');
            this.attributes.repromptSpeech = this.t('LAUNCH_MESSAGE');
            this.emit(':ask', this.attributes.speechOutput, this.attributes.repromptSpeech);
        },
        'Ask': function () {
            const word = this.event.request.intent.slots.word;
            const term = (word && word.value) ? word.value.toLowerCase() : '';

            if (this.event.session.application.applicationId !== APP_ID) {
                this.context.fail('Invalid Application ID');
                return;
            }

            if (!term) {
                this.attributes.speechOutput = this.t('ERROR_MESSAGE');
                this.attributes.repromptSpeech = this.t('HELP_REPROMPT');
                return this.emitWithState('Respond');
            }

            if (term === 'yes' || term == 'yes please') {
                return this.emit('LaunchRequest');
            }
            if (term === 'no' || term == 'no thanks') {
                return this.emit('SessionEndedRequest');
            }

            etty.search(term, (err, response) => {
                this.attributes.speechOutput = response.text;
                response.results.forEach(result => {
                    this.attributes.speechOutput += ' <break time="1s"/> ' + makeResult(term, result);
                });
                this.attributes.speechOutput += ' <break time="1s"/> ' + this.t('SEARCH_AGAIN');
                this.attributes.repromptSpeech = this.t('HELP_REPROMPT');
                this.emitWithState('Respond');
            });
        },
        'Search': function () {
            this.emitWithState('Ask');
        },
        'AMAZON.HelpIntent': function () {
            this.attributes.speechOutput = this.t('HELP_MESSAGE');
            this.attributes.repromptSpeech = this.t('HELP_REPROMPT');
            this.emitWithState('Respond');
        },
        'AMAZON.RepeatIntent': function () {
            this.emitWithState('Respond');
        },
        'AMAZON.StopIntent': function () {
            this.emit('SessionEndedRequest');
        },
        'AMAZON.CancelIntent': function () {
            this.emit('SessionEndedRequest');
        },
        'SessionEndedRequest':function () {
            this.emit(':tell', this.t('STOP_MESSAGE'));
        },
        'Respond': function () {
            this.emit(':ask', this.attributes.speechOutput, this.attributes.repromptSpeech);
        },
        'Unhandled': function () {
            this.emitWithState('AMAZON.HelpIntent');
        }
    };
};<commit_msg>Logging<commit_after>'use strict';
const APP_ID = process.env.APP_ID;
const WORD_TYPES = {
    'n': 'noun',
    'v': 'verb',
    'adv': 'adverb',
    'adj': 'adjective',
    'pron': 'pronoun',
    'interj': 'interjection',
    'conj': 'conjunction',
    'prep': 'preposition'
};

function makeResult(term, item) {
    let type = (WORD_TYPES[item.pos]) ? WORD_TYPES[item.pos] + ' ' : '';
    return term + type + ' ' + item.etymology;
}

module.exports = function(etty) {
    return {
        'LaunchRequest': function () {
            this.attributes.speechOutput = this.t('LAUNCH_MESSAGE');
            this.attributes.repromptSpeech = this.t('LAUNCH_MESSAGE');
            this.emit(':ask', this.attributes.speechOutput, this.attributes.repromptSpeech);
        },
        'Ask': function () {
            const word = this.event.request.intent.slots.word;
            const term = (word && word.value) ? word.value.toLowerCase() : '';

            if (this.event.session.application.applicationId !== APP_ID) {
                this.context.fail('Invalid Application ID');
                return;
            }

            if (!term) {
                this.attributes.speechOutput = this.t('ERROR_MESSAGE');
                this.attributes.repromptSpeech = this.t('HELP_REPROMPT');
                return this.emitWithState('Respond');
            }

            if (term === 'yes' || term == 'yes please') {
                return this.emit('LaunchRequest');
            }
            if (term === 'no' || term == 'no thanks') {
                return this.emit('SessionEndedRequest');
            }

            etty.search(term, (err, response) => {
                /*eslint no-console: 0*/
                console.log('response', response);
                this.attributes.speechOutput = response.text;
                response.results.forEach(result => {
                    this.attributes.speechOutput += ' <break time="1s"/> ' + makeResult(term, result);
                });
                this.attributes.speechOutput += ' <break time="1s"/> ' + this.t('SEARCH_AGAIN');
                this.attributes.repromptSpeech = this.t('HELP_REPROMPT');
                this.emitWithState('Respond');
            });
        },
        'Search': function () {
            this.emitWithState('Ask');
        },
        'AMAZON.HelpIntent': function () {
            this.attributes.speechOutput = this.t('HELP_MESSAGE');
            this.attributes.repromptSpeech = this.t('HELP_REPROMPT');
            this.emitWithState('Respond');
        },
        'AMAZON.RepeatIntent': function () {
            this.emitWithState('Respond');
        },
        'AMAZON.StopIntent': function () {
            this.emit('SessionEndedRequest');
        },
        'AMAZON.CancelIntent': function () {
            this.emit('SessionEndedRequest');
        },
        'SessionEndedRequest':function () {
            this.emit(':tell', this.t('STOP_MESSAGE'));
        },
        'Respond': function () {
            this.emit(':ask', this.attributes.speechOutput, this.attributes.repromptSpeech);
        },
        'Unhandled': function () {
            this.emitWithState('AMAZON.HelpIntent');
        }
    };
};<|endoftext|>


<commit_before>(function(a) {
a.jgrid = a.jgrid || {};
a.extend(a.jgrid,{
        defaults:
        {
            recordtext: "regels {0} - {1} van {2}",
            emptyrecords: "Geen data gevonden.",
            loadtext: "Laden...",
            pgtext: "pagina  {0}  van {1}",
			pgfirst : "Eerste Pagina",
			pglast : "Laatste Pagina",
			pgnext : "Volgende Pagina",
			pgprev : "Vorige Pagina",
			pgrecs : "Records per Pagina",
			showhide: "Schakelen Uitklappen Inklappen Grid"
        },
        search:
        {
            caption: "Zoeken...",
            Find: "Zoek",
            Reset: "Herstellen",
            odata: [{ oper:'eq', text:"gelijk aan"},{ oper:'ne', text:"niet gelijk aan"},{ oper:'lt', text:"kleiner dan"},{ oper:'le', text:"kleiner dan of gelijk aan"},{ oper:'gt', text:"groter dan"},{ oper:'ge', text:"groter dan of gelijk aan"},{ oper:'bw', text:"begint met"},{ oper:'bn', text:"begint niet met"},{ oper:'in', text:"is in"},{ oper:'ni', text:"is niet in"},{ oper:'ew', text:"eindigd met"},{ oper:'en', text:"eindigd niet met"},{ oper:'cn', text:"bevat"},{ oper:'nc', text:"bevat niet"},{ oper:'nu', text:'is null'},{ oper:'nn', text:'is not null'}],
            groupOps: [{ op: "AND", text: "alle" }, { op: "OR", text: "een van de"}],
			operandTitle : "Klim om de zoekterm te selecteren.",
			resetTitle : "Herstel zoekterm"
        },
        edit:
        {
            addCaption: "Nieuw",
            editCaption: "Bewerken",
            bSubmit: "Opslaan",
            bCancel: "Annuleren",
            bClose: "Sluiten",
            saveData: "Er is data aangepast! Wijzigingen opslaan?",
            bYes: "Ja",
            bNo: "Nee",
            bExit: "Sluiten",
            msg:
            {
                required: "Veld is verplicht",
                number: "Voer a.u.b. geldig nummer in",
                minValue: "Waarde moet groter of gelijk zijn aan ",
                maxValue: "Waarde moet kleiner of gelijk zijn aan",
                email: "is geen geldig e-mailadres",
                integer: "Voer a.u.b. een geldig getal in",
                date: "Voer a.u.b. een geldige waarde in",
                url: "is geen geldige URL. Prefix is verplicht ('http://' or 'https://')",
                nodefined : " is niet gedefineerd!",
                novalue : " return waarde is verplicht!",
                customarray : "Aangepaste functie moet array teruggeven!",
                customfcheck : "Aangepaste function moet aanwezig zijn in het geval van aangepaste controle!"
            }
        },
        view:
        {
            caption: "Tonen",
            bClose: "Sluiten"
        },
        del:
        {
            caption: "Verwijderen",
            msg: "Verwijder geselecteerde regel(s)?",
            bSubmit: "Verwijderen",
            bCancel: "Annuleren"
        },
        nav:
        {
            edittext: "",
            edittitle: "Bewerken",
            addtext: "",
            addtitle: "Nieuw",
            deltext: "",
            deltitle: "Verwijderen",
            searchtext: "",
            searchtitle: "Zoeken",
            refreshtext: "",
            refreshtitle: "Vernieuwen",
            alertcap: "Waarschuwing",
            alerttext: "Selecteer a.u.b. een regel",
            viewtext: "",
            viewtitle: "Openen"
        },
        col:
        {
            caption: "Tonen/verbergen kolommen",
            bSubmit: "OK",
            bCancel: "Annuleren"
        },
        errors:
        {
            errcap: "Fout",
            nourl: "Er is geen URL gedefinieerd",
            norecords: "Geen data om te verwerken",
            model: "Lengte van 'colNames' is niet gelijk aan 'colModel'!"
        },
        formatter:
        {
            integer:
            {
                thousandsSeparator: ".",
                defaultValue: "0"
            },
            number:
            {
                decimalSeparator: ",",
                thousandsSeparator: ".",
                decimalPlaces: 2,
                defaultValue: "0.00"
            },
            currency:
            {
                decimalSeparator: ",",
                thousandsSeparator: ".",
                decimalPlaces: 2,
                prefix: "EUR ",
                suffix: "",
                defaultValue: "0.00"
            },
            date:
            {
                dayNames: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"],
                monthNames: ["Jan", "Feb", "Maa", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "October", "November", "December"],
                AmPm: ["am", "pm", "AM", "PM"],
                S: function(b) {
                    return b < 11 || b > 13 ? ["st", "nd", "rd", "th"][Math.min((b - 1) % 10, 3)] : "th"
                },
                srcformat: "Y-m-d",
                newformat: "d/m/Y",
				parseRe : /[#%\\\/:_;.,\t\s-]/,
                masks:
                {
                    ISO8601Long: "Y-m-d H:i:s",
                    ISO8601Short: "Y-m-d",
                    ShortDate: "n/j/Y",
                    LongDate: "l, F d, Y",
                    FullDateTime: "l d F Y G:i:s",
                    MonthDay: "d F",
                    ShortTime: "G:i",
                    LongTime: "G:i:s",
                    SortableDateTime: "Y-m-d\\TH:i:s",
                    UniversalSortableDateTime: "Y-m-d H:i:sO",
                    YearMonth: "F, Y"
                },
                reformatAfterEdit: false,
				userLocalTime : false
            },
            baseLinkUrl: "",
            showAction: "",
            target: "",
            checkbox:
            {
                disabled: true
            },
            idName: "id"
        }
    });
})(jQuery);
<commit_msg>Fixed own typo<commit_after>(function(a) {
a.jgrid = a.jgrid || {};
a.extend(a.jgrid,{
        defaults:
        {
            recordtext: "regels {0} - {1} van {2}",
            emptyrecords: "Geen data gevonden.",
            loadtext: "Laden...",
            pgtext: "pagina  {0}  van {1}",
			pgfirst : "Eerste Pagina",
			pglast : "Laatste Pagina",
			pgnext : "Volgende Pagina",
			pgprev : "Vorige Pagina",
			pgrecs : "Records per Pagina",
			showhide: "Schakelen Uitklappen Inklappen Grid"
        },
        search:
        {
            caption: "Zoeken...",
            Find: "Zoek",
            Reset: "Herstellen",
            odata: [{ oper:'eq', text:"gelijk aan"},{ oper:'ne', text:"niet gelijk aan"},{ oper:'lt', text:"kleiner dan"},{ oper:'le', text:"kleiner dan of gelijk aan"},{ oper:'gt', text:"groter dan"},{ oper:'ge', text:"groter dan of gelijk aan"},{ oper:'bw', text:"begint met"},{ oper:'bn', text:"begint niet met"},{ oper:'in', text:"is in"},{ oper:'ni', text:"is niet in"},{ oper:'ew', text:"eindigd met"},{ oper:'en', text:"eindigd niet met"},{ oper:'cn', text:"bevat"},{ oper:'nc', text:"bevat niet"},{ oper:'nu', text:'is null'},{ oper:'nn', text:'is not null'}],
            groupOps: [{ op: "AND", text: "alle" }, { op: "OR", text: "een van de"}],
			operandTitle : "Klik om de zoekterm te selecteren.",
			resetTitle : "Herstel zoekterm"
        },
        edit:
        {
            addCaption: "Nieuw",
            editCaption: "Bewerken",
            bSubmit: "Opslaan",
            bCancel: "Annuleren",
            bClose: "Sluiten",
            saveData: "Er is data aangepast! Wijzigingen opslaan?",
            bYes: "Ja",
            bNo: "Nee",
            bExit: "Sluiten",
            msg:
            {
                required: "Veld is verplicht",
                number: "Voer a.u.b. geldig nummer in",
                minValue: "Waarde moet groter of gelijk zijn aan ",
                maxValue: "Waarde moet kleiner of gelijk zijn aan",
                email: "is geen geldig e-mailadres",
                integer: "Voer a.u.b. een geldig getal in",
                date: "Voer a.u.b. een geldige waarde in",
                url: "is geen geldige URL. Prefix is verplicht ('http://' or 'https://')",
                nodefined : " is niet gedefineerd!",
                novalue : " return waarde is verplicht!",
                customarray : "Aangepaste functie moet array teruggeven!",
                customfcheck : "Aangepaste function moet aanwezig zijn in het geval van aangepaste controle!"
            }
        },
        view:
        {
            caption: "Tonen",
            bClose: "Sluiten"
        },
        del:
        {
            caption: "Verwijderen",
            msg: "Verwijder geselecteerde regel(s)?",
            bSubmit: "Verwijderen",
            bCancel: "Annuleren"
        },
        nav:
        {
            edittext: "",
            edittitle: "Bewerken",
            addtext: "",
            addtitle: "Nieuw",
            deltext: "",
            deltitle: "Verwijderen",
            searchtext: "",
            searchtitle: "Zoeken",
            refreshtext: "",
            refreshtitle: "Vernieuwen",
            alertcap: "Waarschuwing",
            alerttext: "Selecteer a.u.b. een regel",
            viewtext: "",
            viewtitle: "Openen"
        },
        col:
        {
            caption: "Tonen/verbergen kolommen",
            bSubmit: "OK",
            bCancel: "Annuleren"
        },
        errors:
        {
            errcap: "Fout",
            nourl: "Er is geen URL gedefinieerd",
            norecords: "Geen data om te verwerken",
            model: "Lengte van 'colNames' is niet gelijk aan 'colModel'!"
        },
        formatter:
        {
            integer:
            {
                thousandsSeparator: ".",
                defaultValue: "0"
            },
            number:
            {
                decimalSeparator: ",",
                thousandsSeparator: ".",
                decimalPlaces: 2,
                defaultValue: "0.00"
            },
            currency:
            {
                decimalSeparator: ",",
                thousandsSeparator: ".",
                decimalPlaces: 2,
                prefix: "EUR ",
                suffix: "",
                defaultValue: "0.00"
            },
            date:
            {
                dayNames: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"],
                monthNames: ["Jan", "Feb", "Maa", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "October", "November", "December"],
                AmPm: ["am", "pm", "AM", "PM"],
                S: function(b) {
                    return b < 11 || b > 13 ? ["st", "nd", "rd", "th"][Math.min((b - 1) % 10, 3)] : "th"
                },
                srcformat: "Y-m-d",
                newformat: "d/m/Y",
				parseRe : /[#%\\\/:_;.,\t\s-]/,
                masks:
                {
                    ISO8601Long: "Y-m-d H:i:s",
                    ISO8601Short: "Y-m-d",
                    ShortDate: "n/j/Y",
                    LongDate: "l, F d, Y",
                    FullDateTime: "l d F Y G:i:s",
                    MonthDay: "d F",
                    ShortTime: "G:i",
                    LongTime: "G:i:s",
                    SortableDateTime: "Y-m-d\\TH:i:s",
                    UniversalSortableDateTime: "Y-m-d H:i:sO",
                    YearMonth: "F, Y"
                },
                reformatAfterEdit: false,
				userLocalTime : false
            },
            baseLinkUrl: "",
            showAction: "",
            target: "",
            checkbox:
            {
                disabled: true
            },
            idName: "id"
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>const url = require("url");
const path = require("path");
const fs = require("mz/fs");

const ejs = require("ejs");
const createDebug = require('debug');
const schema = require('validate');

const Route = require('./route');

const debug = createDebug('nails:handlers');
const warn = createDebug('nails:WARNING');

const controllers = {};

function setView({ action, config, rawRoute, routes, method }) {
  return exports.getView(action, config).then(view => {
    routes[rawRoute.type].push({
      method,
      view,
      match: new Route(rawRoute.url)
    });
  });
}

const routeSchema = schema({
  type: {
    type: 'string',
    required: true,
    message: 'type is required and must be a valid HTTP verb',
    match: /GET|HEAD|POST|PUT|DELETE|TRACE|OPTIONS|CONNECT|PATCH/i,
  },
  url: {
    type: 'string',
    required: true,
    message: 'url is required',
  },
  to: {
    type: 'string',
    required: true,
    message: 'to is required',
  },
});

exports = module.exports = class Handler {
  constructor(config) {
    const routes = {
      HEAD: [],
      GET: [],
      POST: [],
      PUT: [],
      PATCH: [],
      DELETE: [],
      OPTIONS: []
    };

    const routesPath = config.appRoot + '/routes';
    debug('loading routes at', routesPath);
    let rawRoutes;
    try {
      rawRoutes = require(routesPath);
    }
    catch (err) {
      /* istanbul ignore next: kinda hard to test */
      if (err.code !== 'MODULE_NOT_FOUND') {
        throw err;
      }
    }

    const promises = [];

    if (rawRoutes) {
      for (let i = 0; i < rawRoutes.length; i++) {
        const errors = routeSchema.validate(rawRoutes[i]);
        if (errors.length > 0) {
          /* istanbul ignore next: router.js always returns valid JSON */
          warn("found route %o: %s", rawRoutes[i], errors.map(error => error.message).join(', '));
        }
        else {
          const action = rawRoutes[i].to;
          const actionSplat = action.split(".");
          if (actionSplat.length === 1) {
            actionSplat.push(undefined);
          }
          const controller = actionSplat.slice(0, -1).join('/');
          const method = actionSplat[actionSplat.length - 1];
          const controllerFile = config.appRoot + '/controllers/' + controller;

          if (controllers[controller]) {
            promises.push(setView({
              action,
              config,
              rawRoute: rawRoutes[i],
              routes,
              method: method ? controllers[controller][method] : controllers[controller]
            }));
          }
          let loaded;
          try {
            loaded = require(controllerFile);
          }
          catch (err) {
            /* istanbul ignore next: kinda hard to test */
            if (err.code === 'MODULE_NOT_FOUND') {
              debug('failed to load controller at', controllerFile);
            } else {
              throw err;
            }
          }
          if (loaded) {
            controllers[controller] = loaded;
            promises.push(setView({
              action,
              config,
              rawRoute: rawRoutes[i],
              routes,
              method: method ? controllers[controller][method] : controllers[controller]
            }));
          }
          else {
            warn("Route", rawRoutes[i], "controller doesn't exist - ignoring.");
          }
        }
      }
      this.routes = routes;
    }
    else {
      /* istanbul ignore next: kinda hard to test */
      throw new ReferenceError("Tried to load the routing file, but it doesn't exist!");
    }
    this.ready = Promise.all(promises);
    this.ready.then(() => {
      debug('loaded', rawRoutes.length, 'routes');
    }).catch(warn);
  }

  getHandler(req) {
    const uri = url.parse(req.url, true);
    const route = this.routes[req.method].find(({ match }) => match.match(uri.pathname));
    return route ? { route, params: route.match.match(uri.pathname) } : null;
  }
};

exports.getStaticContent = (name, config) => {
  const staticPath = path.join(config.appRoot, "static", name);
  return fs.exists(staticPath).then(exists => exists ? fs.readFile(staticPath, 'utf-8') : null).catch(/* istanbul ignore next */ () => null);
};

exports.getView = (route, config) => {
  const action = route.split(".");
  const controller = action[0];
  const method = action[action.length - 1];
  const viewPath = path.join(config.appRoot, "views", controller, method + ".ejs");
  return fs.exists(viewPath).then(exists => {
    if (exists) {
      return fs.readFile(viewPath, 'utf-8').then(contents => ejs.compile(contents, {
        filename: viewPath
      }));
    }
  }).catch(warn);
};

exports.renderer = (req, res, opts) => {
  opts.headers = opts.headers || { 'content-type': 'text/html' };
  const headerNames = Object.keys(opts.headers);
  for (let i = 0; i < headerNames.length; i++) {
    res.setHeader(headerNames[i], opts.headers[headerNames[i]]);
  }

  if (opts.text) {
    opts.content = opts.text;
    delete opts.text;
    exports.renderer(req, res, Object.assign(opts, { headers: { 'content-type': 'text/plain' } }));
    return;
  }
  else if (opts.json) {
    opts.content = JSON.stringify(opts.json);
    delete opts.json;
    exports.renderer(req, res, Object.assign(opts, { headers: { 'content-type': 'application/json' } }));
    return;
  }

  opts.status = opts.status || 200;
  res.statusCode = opts.status;

  if (opts.view) {
    const view = opts.route.view;
    if (view) {
      opts.locals = opts.locals || {};
      res.write(view(opts.locals));
      res.end();
    }
    else {
      warn("handlers.renderer: render specified view: true, but no view present.");
      res.statusCode = 204;
      res.end();
    }
  }
  else if (opts.content) {
    res.write(opts.content);
    res.end();
  }
  else {
    res.statusCode = 204;
    res.end();
  }
};
<commit_msg>Extract extra blocks<commit_after>const url = require("url");
const path = require("path");
const fs = require("mz/fs");

const ejs = require("ejs");
const createDebug = require('debug');
const schema = require('validate');

const Route = require('./route');

const debug = createDebug('nails:handlers');
const warn = createDebug('nails:WARNING');

const controllers = {};

function setView({ action, config, rawRoute, routes, method }) {
  return exports.getView(action, config).then(view => {
    routes[rawRoute.type].push({
      method,
      view,
      match: new Route(rawRoute.url)
    });
  });
}

const routeSchema = schema({
  type: {
    type: 'string',
    required: true,
    message: 'type is required and must be a valid HTTP verb',
    match: /GET|HEAD|POST|PUT|DELETE|TRACE|OPTIONS|CONNECT|PATCH/i,
  },
  url: {
    type: 'string',
    required: true,
    message: 'url is required',
  },
  to: {
    type: 'string',
    required: true,
    message: 'to is required',
  },
});

exports = module.exports = class Handler {
  constructor(config) {
    const routes = {
      HEAD: [],
      GET: [],
      POST: [],
      PUT: [],
      PATCH: [],
      DELETE: [],
      OPTIONS: []
    };

    const routesPath = config.appRoot + '/routes';
    debug('loading routes at', routesPath);
    let rawRoutes;
    try {
      rawRoutes = require(routesPath);
    }
    catch (err) {
      /* istanbul ignore next: kinda hard to test */
      if (err.code !== 'MODULE_NOT_FOUND') {
        throw err;
      }
    }

    const promises = [];

    if (rawRoutes) {
      for (let i = 0; i < rawRoutes.length; i++) {
        const errors = routeSchema.validate(rawRoutes[i]);
        if (errors.length > 0) {
          /* istanbul ignore next: router.js always returns valid JSON */
          warn("found route %o: %s", rawRoutes[i], errors.map(error => error.message).join(', '));
          continue;
        }
        const action = rawRoutes[i].to;
        const actionSplat = action.split(".");
        if (actionSplat.length === 1) {
          actionSplat.push(undefined);
        }
        const controller = actionSplat.slice(0, -1).join('/');
        const method = actionSplat[actionSplat.length - 1];
        const controllerFile = config.appRoot + '/controllers/' + controller;

        if (controllers[controller]) {
          promises.push(setView({
            action,
            config,
            rawRoute: rawRoutes[i],
            routes,
            method: method ? controllers[controller][method] : controllers[controller]
          }));
        }
        let loaded;
        try {
          loaded = require(controllerFile);
        }
        catch (err) {
          /* istanbul ignore next: kinda hard to test */
          if (err.code === 'MODULE_NOT_FOUND') {
            debug('failed to load controller at', controllerFile);
          } else {
            throw err;
          }
        }
        if (!loaded) {
          warn("Route", rawRoutes[i], "controller doesn't exist - ignoring.");
          continue;
        }
        controllers[controller] = loaded;
        promises.push(setView({
          action,
          config,
          rawRoute: rawRoutes[i],
          routes,
          method: method ? controllers[controller][method] : controllers[controller]
        }));
      }
      this.routes = routes;
    }
    else {
      /* istanbul ignore next: kinda hard to test */
      throw new ReferenceError("Tried to load the routing file, but it doesn't exist!");
    }
    this.ready = Promise.all(promises);
    this.ready.then(() => {
      debug('loaded', rawRoutes.length, 'routes');
    }).catch(warn);
  }

  getHandler(req) {
    const uri = url.parse(req.url, true);
    const route = this.routes[req.method].find(({ match }) => match.match(uri.pathname));
    return route ? { route, params: route.match.match(uri.pathname) } : null;
  }
};

exports.getStaticContent = (name, config) => {
  const staticPath = path.join(config.appRoot, "static", name);
  return fs.exists(staticPath).then(exists => exists ? fs.readFile(staticPath, 'utf-8') : null).catch(/* istanbul ignore next */ () => null);
};

exports.getView = (route, config) => {
  const action = route.split(".");
  const controller = action[0];
  const method = action[action.length - 1];
  const viewPath = path.join(config.appRoot, "views", controller, method + ".ejs");
  return fs.exists(viewPath).then(exists => {
    if (exists) {
      return fs.readFile(viewPath, 'utf-8').then(contents => ejs.compile(contents, {
        filename: viewPath
      }));
    }
  }).catch(warn);
};

exports.renderer = (req, res, opts) => {
  opts.headers = opts.headers || { 'content-type': 'text/html' };
  const headerNames = Object.keys(opts.headers);
  for (let i = 0; i < headerNames.length; i++) {
    res.setHeader(headerNames[i], opts.headers[headerNames[i]]);
  }

  if (opts.text) {
    opts.content = opts.text;
    delete opts.text;
    exports.renderer(req, res, Object.assign(opts, { headers: { 'content-type': 'text/plain' } }));
    return;
  }
  else if (opts.json) {
    opts.content = JSON.stringify(opts.json);
    delete opts.json;
    exports.renderer(req, res, Object.assign(opts, { headers: { 'content-type': 'application/json' } }));
    return;
  }

  opts.status = opts.status || 200;
  res.statusCode = opts.status;

  if (opts.view) {
    const view = opts.route.view;
    if (view) {
      opts.locals = opts.locals || {};
      res.write(view(opts.locals));
      res.end();
    }
    else {
      warn("handlers.renderer: render specified view: true, but no view present.");
      res.statusCode = 204;
      res.end();
    }
  }
  else if (opts.content) {
    res.write(opts.content);
    res.end();
  }
  else {
    res.statusCode = 204;
    res.end();
  }
};
<|endoftext|>


<commit_before>iD.operations.Merge = function(selectedIDs, context) {
    var join = iD.actions.Join(selectedIDs),
        merge = iD.actions.Merge(selectedIDs),
        mergePolygon = iD.actions.MergePolygon(selectedIDs);

    var operation = function() {
        var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
            action;

        if (!join.disabled(context.graph())) {
            action = join;
        } else if (!merge.disabled(context.graph())) {
            action = merge;
        } else {
            action = mergePolygon;
        }

        var difference = context.perform(action, annotation);
        context.enter(iD.modes.Select(context, difference.extantIDs()));
    };

    operation.available = function() {
        return selectedIDs.length >= 2;
    };

    operation.disabled = function() {
        return join.disabled(context.graph()) &&
            merge.disabled(context.graph()) &&
            mergePolygon.disabled(context.graph());
    };

    operation.tooltip = function() {
        var j = join.disabled(context.graph()),
            m = merge.disabled(context.graph()),
            p = mergePolygon.disabled(context.graph());

        if (j === 'restriction' && m && p)
            return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});

        if (j && m && p)
            return t('operations.merge.' + j);

        return t('operations.merge.description');
    };

    operation.id = "merge";
    operation.keys = [t('operations.merge.key')];
    operation.title = t('operations.merge.title');

    return operation;
};
<commit_msg>Fix unknown entity error on merge (fixes #1618)<commit_after>iD.operations.Merge = function(selectedIDs, context) {
    var join = iD.actions.Join(selectedIDs),
        merge = iD.actions.Merge(selectedIDs),
        mergePolygon = iD.actions.MergePolygon(selectedIDs);

    var operation = function() {
        var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
            action;

        if (!join.disabled(context.graph())) {
            action = join;
        } else if (!merge.disabled(context.graph())) {
            action = merge;
        } else {
            action = mergePolygon;
        }

        context.perform(action, annotation);
        context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
            .suppressMenu(true));
    };

    operation.available = function() {
        return selectedIDs.length >= 2;
    };

    operation.disabled = function() {
        return join.disabled(context.graph()) &&
            merge.disabled(context.graph()) &&
            mergePolygon.disabled(context.graph());
    };

    operation.tooltip = function() {
        var j = join.disabled(context.graph()),
            m = merge.disabled(context.graph()),
            p = mergePolygon.disabled(context.graph());

        if (j === 'restriction' && m && p)
            return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});

        if (j && m && p)
            return t('operations.merge.' + j);

        return t('operations.merge.description');
    };

    operation.id = "merge";
    operation.keys = [t('operations.merge.key')];
    operation.title = t('operations.merge.title');

    return operation;
};
<|endoftext|>


<commit_before>/*!
 * jQuery ClassySocial
 * www.class.pm
 *
 * Written by Marius Stanciu - Sergiu <marius@class.pm>
 * Extended by Gabriel Zanetti - http://github.com/pupi1985
 * Licensed under the MIT license www.class.pm/LICENSE-MIT
 * Version pupi1985-2.3.0
 *
 */
(function($) {
    $.fn.ClassySocial = function(userOptions) {
        var ClassySocial = function(element, userOptions) {
            var defaultOptions = {
                profiles: {
                    blogger: {
                        url: "http://www.blogger.com/profile/{handle}",
                        tip: 'View my Blogger profile'
                    },
                    deviantart: {
                        url: 'https://{handle}.deviantart.com',
                        tip: 'Check out my DeviantArt page'
                    },
                    dribbble: {
                        url: 'http://dribbble.com/{handle}',
                        tip: 'View my Dribbble page'
                    },
                    email: {
                        url: 'mailto:{handle}',
                        tip: 'Send me an e-mail'
                    },
                    facebook: {
                        url: 'http://www.facebook.com/{handle}',
                        tip: 'View my Facebook page',
                    },
                    flickr: {
                        url: 'http://www.flickr.com/photos/{handle}',
                        tip: 'View my Flickr images'
                    },
                    github: {
                        url: "https://www.github.com/{handle}",
                        tip: 'View my GitHub developer profile'
                    },
                    googleplus: {
                        url: 'https://plus.google.com/{handle}',
                        tip: 'View my Google Plus profile'
                    },
                    instagram: {
                        url: 'http://instagram.com/{handle}',
                        tip: 'View my Instagram profile'
                    },
                    linkedin: {
                        url: 'http://www.linkedin.com/profile/view?id={handle}',
                        tip: 'View my LinkedIn profile'
                    },
                    pinterest: {
                        url: 'http://pinterest.com/{handle}',
                        tip: 'View my Pinterest profile'
                    },
                    skype: {
                        url: 'skype:{handle}?userinfo',
                        tip: 'Call me on Skype'
                    },
                    socl: {
                        url: 'http://www.so.cl/#/profile/{handle}',
                        tip: 'View my Socl profile'
                    },
                    steam: {
                        url: 'http://steamcommunity.com/profiles/{handle}',
                        tip: 'View my Steam profile'
                    },
                    twitter: {
                        url: 'https://twitter.com/{handle}',
                        tip: 'Check out my Twitter profile'
                    },
                    vimeo: {
                        url: 'http://vimeo.com/{handle}',
                        tip: 'View my Vimeo profile'
                    },
                    wordpress: {
                        url: 'http://{handle}.wordpress.com',
                        tip: 'View my wordpress.com profile'
                    },
                    yahoo: {
                        url: 'http://profile.yahoo.com/y/pulse/{handle}',
                        tip: 'Check out my Yahoo profile'
                    },
                    youtube: {
                        url: 'http://www.youtube.com/user/{handle}',
                        tip: 'Check out my Youtube profile'
                    }
                },
                mainButton: {
                    tip: 'Find me here!',
                    image: {
                        type: 'default',  // Can be 'profile' or 'default'
                        name: 'facebook'  // Only needed when type is 'profile'. Requires 'imageUrl' set in the given profile
                    },
                },
                theme: 'default',
                orientation: 'arc',
                arcStart: 0,
                arcLength: 360,
                arcRadius: 80,
                gap: 80
            };

            var options = {};
            $.extend(true, options, defaultOptions, userOptions);

            var el = $(element);
            var imageUrl = null;

            this.__constructor = function() {
                el.addClass('bubble');
                var template = this.template;
                var containerTemplate = template.containerWithoutProfileImage;
                if (options.mainButton.image.type === 'profile') {
                    var profileId = options.mainButton.image.name;
                    var profileImage = options.profiles[profileId].imageUrl;
                    if (profileImage) {
                        imageUrl = profileImage.replace(/\{handle\}/gi, options.profiles[profileId].handle);
                        containerTemplate = template.containerWithProfileImage;
                    }
                }
                el.html(containerTemplate
                    .replace(/\{mainButtonImageUrl\}/gi, imageUrl)
                    .replace(/\{theme\}/gi, options.theme)
                    .replace(/\{mainButtonTip\}/gi, options.mainButton.tip)
                );
                var container = el.find(".scontainer");
                $.each(options.profiles, function(profileKey, profile){
                    if (profile.url && profile.handle) {
                        var u = profile.url.replace(/\{handle\}/gi, profile.handle);
                        var a = template.button
                            .replace(/\{url\}/gi, u)
                            .replace(/\{tip\}/gi, profile.tip)
                            .replace(/\{network\}/gi, profileKey)
                        ;
                        container.append($(a));
                    }

                });
                return this._build(template);
            };

            this._build = function(template) {
                var orientationFunction = template.orientations[options.orientation];
                el.find('.smain').click(orientationFunction);
                return this;
            };

            this.template = {
                containerWithProfileImage:
                    '' +
                        '' +
                    '' +
                    '

',
                containerWithoutProfileImage:
                    '' +
                    '

',
                button: '',
                orientations: {
                    arc: function() {
                        if ($(this).hasClass('disabled')) {
                            return;
                        }
                        var e = 250, t = 250, r = el.find('.sbutton').length, i = e + (r - 1) * t, s = 0;
                        var o = $(this).outerWidth(), l = $(this).outerHeight();
                        var c = el.find('.sbutton:eq(0)').outerWidth(), h = el.find('.sbutton:eq(0)').outerHeight();
                        var p = (o - c) / 2, d = (l - h) / 2;
                        if (!$(this).hasClass('active')) {
                            $(this).addClass('disabled').delay(i).queue(function(e) {
                                $(this).removeClass('disabled').addClass('active');
                                e();
                            });
                            var v = options.arcLength / r, m = options.arcStart + v / 2;
                            el.find('.sbutton').each(function() {
                                var n = m / 180 * Math.PI, r = p + options.arcRadius * Math.cos(n), i = d + options.arcRadius * Math.sin(n);
                                $(this).css({
                                    display: 'block',
                                    left: p + 'px',
                                    top: d + 'px'
                                }).stop().delay(t * s).animate({
                                    left: r + 'px',
                                    top: i + 'px'
                                }, e);
                                m += v;
                                s++;
                            });
                        } else {
                            s = r - 1;
                            $(this).addClass('disabled').delay(i).queue(function(e) {
                                $(this).removeClass('disabled').removeClass('active');
                                e();
                            });
                            el.find('.sbutton').each(function() {
                                $(this).stop().delay(t * s).animate({
                                    left: p,
                                    top: d
                                }, e);
                                s--;
                            });
                        }
                    },
                    linedown: function() {
                        if ($(this).hasClass('disabled')) {
                            return;
                        }
                        var e = 500, t = 250, r = el.find('.sbutton').length, i = options.gap, s = e + (r - 1) * t, o = 1;
                        var a = $(this).outerWidth(), f = $(this).outerHeight();
                        var c = el.find('.sbutton:eq(0)').outerWidth(), h = el.find('.sbutton:eq(0)').outerHeight();
                        var p = (a - c) / 2, d = (f - h) / 2, v = options.arcStart / 180 * Math.PI;
                        if (!$(this).hasClass('active')) {
                            $(this).addClass('disabled').delay(s).queue(function(e) {
                                $(this).removeClass('disabled').addClass('active');
                                e();
                            });
                            el.find('.sbutton').each(function() {
                                var n = p + (p + i * o) * Math.cos(v), r = d + (d + i * o) * Math.sin(v);
                                $(this).css({
                                    display: 'block',
                                    left: d + 'px',
                                    top: p + 'px'
                                }).stop().delay(t * o).animate({
                                    left: r + 'px',
                                    top: n + 'px'
                                }, e);
                                o++;
                            });
                        } else {
                            o = r;
                            $(this).addClass('disabled').delay(s).queue(function(e) {
                                $(this).removeClass('disabled').removeClass('active');
                                e();
                            });
                            el.find('.sbutton').each(function() {
                                $(this).stop().delay(t * o).animate({
                                    left: d,
                                    top: p
                                }, e);
                                o--;
                            });
                        }
                    },
                    line: function() {
                        if ($(this).hasClass('disabled')) {
                            return;
                        }
                        var e = 500, t = 250, r = el.find('.sbutton').length, i = options.gap, s = e + (r - 1) * t, o = 1;
                        var a = $(this).outerWidth(), f = $(this).outerHeight();
                        var c = el.find('.sbutton:eq(0)').outerWidth(), h = el.find('.sbutton:eq(0)').outerHeight();
                        var p = (a - c) / 2, d = (f - h) / 2, v = options.arcStart / 180 * Math.PI;
                        if (!$(this).hasClass('active')) {
                            $(this).addClass('disabled').delay(s).queue(function(e) {
                                $(this).removeClass('disabled').addClass('active');
                                e();
                            });
                            el.find('.sbutton').each(function() {
                                var n = p + (p + i * o) * Math.cos(v), r = d + (d + i * o) * Math.sin(v);
                                $(this).css({
                                    display: 'block',
                                    left: p + 'px',
                                    top: d + 'px'
                                }).stop().delay(t * o).animate({
                                    left: n + 'px',
                                    top: r + 'px'
                                }, e);
                                o++;
                            });
                        } else {
                            o = r;
                            $(this).addClass('disabled').delay(s).queue(function(e) {
                                $(this).removeClass('disabled').removeClass('active');
                                e();
                            });
                            el.find('.sbutton').each(function() {
                                $(this).stop().delay(t * o).animate({
                                    left: p,
                                    top: d
                                }, e);
                                o--;
                            });
                        }
                    }
                }
            };
            return this.__constructor();
        };
        return this.each(function() {
            return new ClassySocial(this, userOptions);
        });
    };
})(jQuery);<commit_msg>Removed linedown function and performed minor refactorings<commit_after>/*!
 * jQuery ClassySocial
 * www.class.pm
 *
 * Written by Marius Stanciu - Sergiu <marius@class.pm>
 * Extended by Gabriel Zanetti - http://github.com/pupi1985
 * Licensed under the MIT license www.class.pm/LICENSE-MIT
 * Version pupi1985-2.3.0
 *
 */
(function($) {
    $.fn.ClassySocial = function(userOptions) {
        var ClassySocial = function(element, userOptions) {
            var defaultOptions = {
                profiles: {
                    blogger: {
                        url: "http://www.blogger.com/profile/{handle}",
                        tip: 'View my Blogger profile'
                    },
                    deviantart: {
                        url: 'https://{handle}.deviantart.com',
                        tip: 'Check out my DeviantArt page'
                    },
                    dribbble: {
                        url: 'http://dribbble.com/{handle}',
                        tip: 'View my Dribbble page'
                    },
                    email: {
                        url: 'mailto:{handle}',
                        tip: 'Send me an e-mail'
                    },
                    facebook: {
                        url: 'http://www.facebook.com/{handle}',
                        tip: 'View my Facebook page'
                    },
                    flickr: {
                        url: 'http://www.flickr.com/photos/{handle}',
                        tip: 'View my Flickr images'
                    },
                    github: {
                        url: "https://www.github.com/{handle}",
                        tip: 'View my GitHub developer profile'
                    },
                    googleplus: {
                        url: 'https://plus.google.com/{handle}',
                        tip: 'View my Google Plus profile'
                    },
                    instagram: {
                        url: 'http://instagram.com/{handle}',
                        tip: 'View my Instagram profile'
                    },
                    linkedin: {
                        url: 'http://www.linkedin.com/profile/view?id={handle}',
                        tip: 'View my LinkedIn profile'
                    },
                    pinterest: {
                        url: 'http://pinterest.com/{handle}',
                        tip: 'View my Pinterest profile'
                    },
                    skype: {
                        url: 'skype:{handle}?userinfo',
                        tip: 'Call me on Skype'
                    },
                    socl: {
                        url: 'http://www.so.cl/#/profile/{handle}',
                        tip: 'View my Socl profile'
                    },
                    steam: {
                        url: 'http://steamcommunity.com/profiles/{handle}',
                        tip: 'View my Steam profile'
                    },
                    twitter: {
                        url: 'https://twitter.com/{handle}',
                        tip: 'Check out my Twitter profile'
                    },
                    vimeo: {
                        url: 'http://vimeo.com/{handle}',
                        tip: 'View my Vimeo profile'
                    },
                    wordpress: {
                        url: 'http://{handle}.wordpress.com',
                        tip: 'View my wordpress.com profile'
                    },
                    yahoo: {
                        url: 'http://profile.yahoo.com/y/pulse/{handle}',
                        tip: 'Check out my Yahoo profile'
                    },
                    youtube: {
                        url: 'http://www.youtube.com/user/{handle}',
                        tip: 'Check out my Youtube profile'
                    }
                },
                mainButton: {
                    tip: 'Find me here!',
                    image: {
                        type: 'default',  // Can be 'profile' or 'default'
                        name: 'facebook'  // Only needed when type is 'profile'. Requires 'imageUrl' set in the given profile
                    }
                },
                theme: 'default',
                orientation: 'arc',
                arcStart: 0,
                arcLength: 360,
                arcRadius: 80,
                gap: 80
            };

            var options = {};
            $.extend(true, options, defaultOptions, userOptions);

            var el = $(element);
            var imageUrl = null;

            this.__constructor = function() {
                el.addClass('bubble');
                var template = this.template;
                var containerTemplate = template.containerWithoutProfileImage;
                if (options.mainButton.image.type === 'profile') {
                    var profileId = options.mainButton.image.name;
                    var profileImage = options.profiles[profileId].imageUrl;
                    if (profileImage) {
                        imageUrl = profileImage.replace(/\{handle\}/gi, options.profiles[profileId].handle);
                        containerTemplate = template.containerWithProfileImage;
                    }
                }
                el.html(containerTemplate
                    .replace(/\{mainButtonImageUrl\}/gi, imageUrl)
                    .replace(/\{theme\}/gi, options.theme)
                    .replace(/\{mainButtonTip\}/gi, options.mainButton.tip)
                );
                var container = el.find(".scontainer");
                $.each(options.profiles, function(profileKey, profile){
                    if (profile.url && profile.handle) {
                        var u = profile.url.replace(/\{handle\}/gi, profile.handle);
                        var a = template.button
                            .replace(/\{url\}/gi, u)
                            .replace(/\{tip\}/gi, profile.tip)
                            .replace(/\{network\}/gi, profileKey)
                        ;
                        container.append($(a));
                    }

                });
                return this._build(template);
            };

            this._build = function(template) {
                var orientationFunction = template.orientations[options.orientation];
                el.find('.smain').click(orientationFunction);
                return this;
            };

			var _orientationDisable = function(element, e, i, s, p, d, t) {
				$(element).addClass('disabled').delay(i).queue(function(e1) {
					$(this).removeClass('disabled').removeClass('active');
					e1();
				});
				el.find('.sbutton').each(function() {
					$(this).stop().delay(t * s).animate({
						left: p,
						top: d
					}, e);
					s--;
				});
            };

			var _orientationActivate = function(element, p, d, delay, n, r, e) {
				$(element).css({
					display: 'block',
					left: p + 'px',
					top: d + 'px'
				}).stop().delay(delay).animate({
					left: n + 'px',
					top: r + 'px'
				}, e);
            };

            this.template = {
                containerWithProfileImage:
                    '' +
                        '' +
                    '' +
                    '

',
                containerWithoutProfileImage:
                    '' +
                    '

',
                button: '',
                orientations: {
                    arc: function() {
                        if ($(this).hasClass('disabled')) {
                            return;
                        }
                        var e = 250, t = 250, r = el.find('.sbutton').length, i = e + (r - 1) * t, s = 0;
                        var p = ($(this).outerWidth() - el.find('.sbutton:eq(0)').outerWidth()) / 2;
						var d = ($(this).outerHeight() - el.find('.sbutton:eq(0)').outerHeight()) / 2;

                        if (!$(this).hasClass('active')) {
                            $(this).addClass('disabled').delay(i).queue(function(e) {
                                $(this).removeClass('disabled').addClass('active');
                                e();
                            });
                            var v = options.arcLength / r
							var m = options.arcStart + v / 2;
                            el.find('.sbutton').each(function() {
                                var n = m / 180 * Math.PI;
								var r = p + options.arcRadius * Math.cos(n);
								var i = d + options.arcRadius * Math.sin(n);
								_orientationActivate(this, p, d, t * s, r, i, e);
                                m += v;
                                s++;
                            });
                        } else {
							_orientationDisable(this, e, i, r - 1, p, d, t);
                        }
                    },
                    line: function() {
                        if ($(this).hasClass('disabled')) {
                            return;
                        }
                        var e = 500, t = 250, r = el.find('.sbutton').length, i = e + (r - 1) * t, s = 1;
                        var p = ($(this).outerWidth() - el.find('.sbutton:eq(0)').outerWidth()) / 2;
						var d = ($(this).outerHeight() - el.find('.sbutton:eq(0)').outerHeight()) / 2;
						var v = options.arcStart / 180 * Math.PI;

                        if (!$(this).hasClass('active')) {
                            $(this).addClass('disabled').delay(i).queue(function(e) {
                                $(this).removeClass('disabled').addClass('active');
                                e();
                            });
                            el.find('.sbutton').each(function() {
								var gap = options.gap * s;
                                var n = p + (p + gap) * Math.cos(v);
								var r = d + (d + gap) * Math.sin(v);
								_orientationActivate(this, p, d, t * s, n, r, e);
                                s++;
                            });
                        } else {
							_orientationDisable(this, e, i, r, p, d, t);
                        }
                    }
                }
            };
            return this.__constructor();
        };
        return this.each(function() {
            return new ClassySocial(this, userOptions);
        });
    };
})(jQuery);<|endoftext|>