text:
'use strict';

/* global

    -VALID_CLASS,
    -INVALID_CLASS,
    -PRISTINE_CLASS,
    -DIRTY_CLASS
*/

var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/;
var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
var TIME_REGEXP = /^(\d\d):(\d\d)$/;
var DEFAULT_REGEXP = /(\b|^)default(\b|$)/;

var inputType = {

  /**
   * @ngdoc input
   * @name input[text]
   *
   * @description
   * Standard HTML text input with angular data binding.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} required Adds `required` validation error key if the value is not entered.
   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   *    `required` when you want to data-bind to the `required` attribute.
   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
   *    minlength.
   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
   *    maxlength.
   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
   *    patterns defined as scope expressions.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
   *
   * @example
      <example name="text-input-directive">
        <file name="index.html">

         <form name="myForm" ng-controller="Ctrl">
           Single word: <input type="text" name="input" ng-model="text"
                               ng-pattern="word" required ng-trim="false">

             Required!

             Single word only!

           <tt>text = {{text}}</tt>

           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

           <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

           <tt>myForm.$valid = {{myForm.$valid}}</tt>

           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

          </form>
        </file>
        <file name="protractor.js" type="protractor">
          var text = element(by.binding('text'));
          var valid = element(by.binding('myForm.input.$valid'));
          var input = element(by.model('text'));

          it('should initialize to model', function() {
            expect(text.getText()).toContain('guest');
            expect(valid.getText()).toContain('true');
          });

          it('should be invalid if empty', function() {
            input.clear();
            input.sendKeys('');

            expect(text.getText()).toEqual('text =');
            expect(valid.getText()).toContain('false');
          });

          it('should be invalid if multi word', function() {
            input.clear();
            input.sendKeys('hello world');

            expect(valid.getText()).toContain('false');
          });
        </file>
      </example>
   */
  'text': textInputType,

    /**
     * @ngdoc input
     * @name input[date]
     *
     * @description
     * Input with date validation and transformation. In browsers that do not yet support
     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
     * date format (yyyy-MM-dd), for example: `2009-01-06`. The model must always be a Date object.
     *
     * @param {string} ngModel Assignable angular expression to data-bind to.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
     * valid ISO date string (yyyy-MM-dd).
     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
     * a valid ISO date string (yyyy-MM-dd).
     * @param {string=} required Sets `required` validation error key if the value is not entered.
     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
     *    `required` when you want to data-bind to the `required` attribute.
     * @param {string=} ngChange Angular expression to be executed when input changes due to user
     *    interaction with the input element.
     *
     * @example
     <example name="date-input-directive">
     <file name="index.html">

       <form name="myForm" ng-controller="Ctrl as dateCtrl">
          Pick a date between in 2013:
          <input type="date" id="exampleInput" name="input" ng-model="value"
              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />

              Required!

              Not a valid date!
           <tt>value = {{value | date: "yyyy-MM-dd"}}</tt>

           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

           <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

           <tt>myForm.$valid = {{myForm.$valid}}</tt>

           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

       </form>
     </file>
     <file name="protractor.js" type="protractor">
        var value = element(by.binding('value | date: "yyyy-MM-dd"'));
        var valid = element(by.binding('myForm.input.$valid'));
        var input = element(by.model('value'));

        // currently protractor/webdriver does not support
        // sending keys to all known HTML5 input controls
        // for various browsers (see https://github.com/angular/protractor/issues/562).
        function setInput(val) {
          // set the value of the element and force validation.
          var scr = "var ipt = document.getElementById('exampleInput'); " +
          "ipt.value = '" + val + "';" +
          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
          browser.executeScript(scr);
        }

        it('should initialize to model', function() {
          expect(value.getText()).toContain('2013-10-22');
          expect(valid.getText()).toContain('myForm.input.$valid = true');
        });

        it('should be invalid if empty', function() {
          setInput('');
          expect(value.getText()).toEqual('value =');
          expect(valid.getText()).toContain('myForm.input.$valid = false');
        });

        it('should be invalid if over max', function() {
          setInput('2015-01-01');
          expect(value.getText()).toContain('');
          expect(valid.getText()).toContain('myForm.input.$valid = false');
        });
     </file>
     </example>f
     */
  'date': createDateInputType('date', DATE_REGEXP,
         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
         'yyyy-MM-dd'),

   /**
    * @ngdoc input
    * @name input[dateTimeLocal]
    *
    * @description
    * Input with datetime validation and transformation. In browsers that do not yet support
    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
    * local datetime format (yyyy-MM-ddTHH:mm), for example: `2010-12-28T14:57`. The model must be a Date object.
    *
    * @param {string} ngModel Assignable angular expression to data-bind to.
    * @param {string=} name Property name of the form under which the control is published.
    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
    * valid ISO datetime format (yyyy-MM-ddTHH:mm).
    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
    * a valid ISO datetime format (yyyy-MM-ddTHH:mm).
    * @param {string=} required Sets `required` validation error key if the value is not entered.
    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
    *    `required` when you want to data-bind to the `required` attribute.
    * @param {string=} ngChange Angular expression to be executed when input changes due to user
    *    interaction with the input element.
    *
    * @example
    <example name="datetimelocal-input-directive">
    <file name="index.html">

      <form name="myForm" ng-controller="Ctrl as dateCtrl">
        Pick a date between in 2013:
        <input type="datetime-local" id="exampleInput" name="input" ng-model="value"
            placeholder="yyyy-MM-ddTHH:mm" min="2001-01-01T00:00" max="2013-12-31T00:00" required />

            Required!

            Not a valid date!
        <tt>value = {{value | date: "yyyy-MM-ddTHH:mm"}}</tt>

        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

        <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

        <tt>myForm.$valid = {{myForm.$valid}}</tt>

        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

      </form>
    </file>
    <file name="protractor.js" type="protractor">
      var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm"'));
      var valid = element(by.binding('myForm.input.$valid'));
      var input = element(by.model('value'));

      // currently protractor/webdriver does not support
      // sending keys to all known HTML5 input controls
      // for various browsers (https://github.com/angular/protractor/issues/562).
      function setInput(val) {
        // set the value of the element and force validation.
        var scr = "var ipt = document.getElementById('exampleInput'); " +
        "ipt.value = '" + val + "';" +
        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
        browser.executeScript(scr);
      }

      it('should initialize to model', function() {
        expect(value.getText()).toContain('2010-12-28T14:57');
        expect(valid.getText()).toContain('myForm.input.$valid = true');
      });

      it('should be invalid if empty', function() {
        setInput('');
        expect(value.getText()).toEqual('value =');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });

      it('should be invalid if over max', function() {
        setInput('2015-01-01T23:59');
        expect(value.getText()).toContain('');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });
    </file>
    </example>
    */
  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm']),
      'yyyy-MM-ddTHH:mm'),

  /**
   * @ngdoc input
   * @name input[time]
   *
   * @description
   * Input with time validation and transformation. In browsers that do not yet support
   * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
   * local time format (HH:mm), for example: `14:57`. Model must be a Date object. This binding will always output a
   * Date object to the model of January 1, 1900, or local date `new Date(0, 0, 1, HH, mm)`.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
   * valid ISO time format (HH:mm).
   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
   * valid ISO time format (HH:mm).
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   *    `required` when you want to data-bind to the `required` attribute.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
   <example name="time-input-directive">
   <file name="index.html">

     <form name="myForm" ng-controller="Ctrl as dateCtrl">
        Pick a between 8am and 5pm:
        <input type="time" id="exampleInput" name="input" ng-model="value"
            placeholder="HH:mm" min="08:00" max="17:00" required />

            Required!

            Not a valid date!
        <tt>value = {{value | date: "HH:mm"}}</tt>

        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

        <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

        <tt>myForm.$valid = {{myForm.$valid}}</tt>

        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

     </form>
   </file>
   <file name="protractor.js" type="protractor">
      var value = element(by.binding('value | date: "HH:mm"'));
      var valid = element(by.binding('myForm.input.$valid'));
      var input = element(by.model('value'));

      // currently protractor/webdriver does not support
      // sending keys to all known HTML5 input controls
      // for various browsers (https://github.com/angular/protractor/issues/562).
      function setInput(val) {
        // set the value of the element and force validation.
        var scr = "var ipt = document.getElementById('exampleInput'); " +
        "ipt.value = '" + val + "';" +
        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
        browser.executeScript(scr);
      }

      it('should initialize to model', function() {
        expect(value.getText()).toContain('14:57');
        expect(valid.getText()).toContain('myForm.input.$valid = true');
      });

      it('should be invalid if empty', function() {
        setInput('');
        expect(value.getText()).toEqual('value =');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });

      it('should be invalid if over max', function() {
        setInput('23:59');
        expect(value.getText()).toContain('');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });
   </file>
   </example>
   */
  'time': createDateInputType('time', TIME_REGEXP,
      createDateParser(TIME_REGEXP, ['HH', 'mm']),
     'HH:mm'),

   /**
    * @ngdoc input
    * @name input[week]
    *
    * @description
    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
    * week format (yyyy-W##), for example: `2013-W02`. The model must always be a Date object.
    *
    * @param {string} ngModel Assignable angular expression to data-bind to.
    * @param {string=} name Property name of the form under which the control is published.
    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
    * valid ISO week format (yyyy-W##).
    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
    * a valid ISO week format (yyyy-W##).
    * @param {string=} required Sets `required` validation error key if the value is not entered.
    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
    *    `required` when you want to data-bind to the `required` attribute.
    * @param {string=} ngChange Angular expression to be executed when input changes due to user
    *    interaction with the input element.
    *
    * @example
    <example name="week-input-directive">
    <file name="index.html">

      <form name="myForm" ng-controller="Ctrl as dateCtrl">
        Pick a date between in 2013:
        <input id="exampleInput" type="week" name="input" ng-model="value"
            placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />

            Required!

            Not a valid date!
        <tt>value = {{value | date: "yyyy-Www"}}</tt>

        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

        <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

        <tt>myForm.$valid = {{myForm.$valid}}</tt>

        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

      </form>
    </file>
    <file name="protractor.js" type="protractor">
      var value = element(by.binding('value | date: "yyyy-Www"'));
      var valid = element(by.binding('myForm.input.$valid'));
      var input = element(by.model('value'));

      // currently protractor/webdriver does not support
      // sending keys to all known HTML5 input controls
      // for various browsers (https://github.com/angular/protractor/issues/562).
      function setInput(val) {
        // set the value of the element and force validation.
        var scr = "var ipt = document.getElementById('exampleInput'); " +
        "ipt.value = '" + val + "';" +
        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
        browser.executeScript(scr);
      }

      it('should initialize to model', function() {
        expect(value.getText()).toContain('2013-W01');
        expect(valid.getText()).toContain('myForm.input.$valid = true');
      });

      it('should be invalid if empty', function() {
        setInput('');
        expect(value.getText()).toEqual('value =');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });

      it('should be invalid if over max', function() {
        setInput('2015-W01');
        expect(value.getText()).toContain('');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });
    </file>
    </example>
    */
  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),

  /**
   * @ngdoc input
   * @name input[month]
   *
   * @description
   * Input with month validation and transformation. In browsers that do not yet support
   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
   * month format (yyyy-MM), for example: `2009-01`. The model must always be a Date object. In the event the model is
   * not set to the first of the month, the first of that model's month is assumed.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
   * a valid ISO month format (yyyy-MM).
   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
   * be a valid ISO month format (yyyy-MM).
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   *    `required` when you want to data-bind to the `required` attribute.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
   <example name="month-input-directive">
   <file name="index.html">

     <form name="myForm" ng-controller="Ctrl as dateCtrl">
       Pick a month int 2013:
       <input id="exampleInput" type="month" name="input" ng-model="value"
          placeholder="yyyy-MM" min="2013-01" max="2013-12" required />

          Required!

          Not a valid month!
       <tt>value = {{value | date: "yyyy-MM"}}</tt>

       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

       <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

       <tt>myForm.$valid = {{myForm.$valid}}</tt>

       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

     </form>
   </file>
   <file name="protractor.js" type="protractor">
      var value = element(by.binding('value | date: "yyyy-MM"'));
      var valid = element(by.binding('myForm.input.$valid'));
      var input = element(by.model('value'));

      // currently protractor/webdriver does not support
      // sending keys to all known HTML5 input controls
      // for various browsers (https://github.com/angular/protractor/issues/562).
      function setInput(val) {
        // set the value of the element and force validation.
        var scr = "var ipt = document.getElementById('exampleInput'); " +
        "ipt.value = '" + val + "';" +
        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
        browser.executeScript(scr);
      }

      it('should initialize to model', function() {
        expect(value.getText()).toContain('2013-10');
        expect(valid.getText()).toContain('myForm.input.$valid = true');
      });

      it('should be invalid if empty', function() {
        setInput('');
        expect(value.getText()).toEqual('value =');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });

      it('should be invalid if over max', function() {
        setInput('2015-01');
        expect(value.getText()).toContain('');
        expect(valid.getText()).toContain('myForm.input.$valid = false');
      });
   </file>
   </example>
   */
  'month': createDateInputType('month', MONTH_REGEXP,
     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
     'yyyy-MM'),

  /**
   * @ngdoc input
   * @name input[number]
   *
   * @description
   * Text input with number validation and transformation. Sets the `number` validation
   * error if not a valid number.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   *    `required` when you want to data-bind to the `required` attribute.
   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
   *    minlength.
   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
   *    maxlength.
   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
   *    patterns defined as scope expressions.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
      <example name="number-input-directive">
        <file name="index.html">

         <form name="myForm" ng-controller="Ctrl">
           Number: <input type="number" name="input" ng-model="value"
                          min="0" max="99" required>

             Required!

             Not valid number!
           <tt>value = {{value}}</tt>

           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

           <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

           <tt>myForm.$valid = {{myForm.$valid}}</tt>

           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

          </form>
        </file>
        <file name="protractor.js" type="protractor">
          var value = element(by.binding('value'));
          var valid = element(by.binding('myForm.input.$valid'));
          var input = element(by.model('value'));

          it('should initialize to model', function() {
            expect(value.getText()).toContain('12');
            expect(valid.getText()).toContain('true');
          });

          it('should be invalid if empty', function() {
            input.clear();
            input.sendKeys('');
            expect(value.getText()).toEqual('value =');
            expect(valid.getText()).toContain('false');
          });

          it('should be invalid if over max', function() {
            input.clear();
            input.sendKeys('123');
            expect(value.getText()).toEqual('value =');
            expect(valid.getText()).toContain('false');
          });
        </file>
      </example>
   */
  'number': numberInputType,

  /**
   * @ngdoc input
   * @name input[url]
   *
   * @description
   * Text input with URL validation. Sets the `url` validation error key if the content is not a
   * valid URL.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   *    `required` when you want to data-bind to the `required` attribute.
   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
   *    minlength.
   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
   *    maxlength.
   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
   *    patterns defined as scope expressions.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
      <example name="url-input-directive">
        <file name="index.html">

         <form name="myForm" ng-controller="Ctrl">
           URL: <input type="url" name="input" ng-model="text" required>

             Required!

             Not valid url!
           <tt>text = {{text}}</tt>

           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

           <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

           <tt>myForm.$valid = {{myForm.$valid}}</tt>

           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt>

          </form>
        </file>
        <file name="protractor.js" type="protractor">
          var text = element(by.binding('text'));
          var valid = element(by.binding('myForm.input.$valid'));
          var input = element(by.model('text'));

          it('should initialize to model', function() {
            expect(text.getText()).toContain('http://google.com');
            expect(valid.getText()).toContain('true');
          });

          it('should be invalid if empty', function() {
            input.clear();
            input.sendKeys('');

            expect(text.getText()).toEqual('text =');
            expect(valid.getText()).toContain('false');
          });

          it('should be invalid if not url', function() {
            input.clear();
            input.sendKeys('box');

            expect(valid.getText()).toContain('false');
          });
        </file>
      </example>
   */
  'url': urlInputType,

  /**
   * @ngdoc input
   * @name input[email]
   *
   * @description
   * Text input with email validation. Sets the `email` validation error key if not a valid email
   * address.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   *    `required` when you want to data-bind to the `required` attribute.
   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
   *    minlength.
   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
   *    maxlength.
   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
   *    patterns defined as scope expressions.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
      <example name="email-input-directive">
        <file name="index.html">

           <form name="myForm" ng-controller="Ctrl">
             Email: <input type="email" name="input" ng-model="text" required>

               Required!

               Not valid email!
             <tt>text = {{text}}</tt>

             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt>

             <tt>myForm.input.$error = {{myForm.input.$error}}</tt>

             <tt>myForm.$valid = {{myForm.$valid}}</tt>

             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt>

           </form>
         </file>
        <file name="protractor.js" type="protractor">
          var text = element(by.binding('text'));
          var valid = element(by.binding('myForm.input.$valid'));
          var input = element(by.model('text'));

          it('should initialize to model', function() {
            expect(text.getText()).toContain('me@example.com');
            expect(valid.getText()).toContain('true');
          });

          it('should be invalid if empty', function() {
            input.clear();
            input.sendKeys('');
            expect(text.getText()).toEqual('text =');
            expect(valid.getText()).toContain('false');
          });

          it('should be invalid if not email', function() {
            input.clear();
            input.sendKeys('xxx');

            expect(valid.getText()).toContain('false');
          });
        </file>
      </example>
   */
  'email': emailInputType,

  /**
   * @ngdoc input
   * @name input[radio]
   *
   * @description
   * HTML radio button.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string} value The value to which the expression should be set when selected.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   * @param {string} ngValue Angular expression which sets the value to which the expression should
   *    be set when selected.
   *
   * @example
      <example name="radio-input-directive">
        <file name="index.html">

         <form name="myForm" ng-controller="Ctrl">
           <input type="radio" ng-model="color" value="red">  Red

           <input type="radio" ng-model="color" ng-value="specialValue"> Green

           <input type="radio" ng-model="color" value="blue"> Blue

           <tt>color = {{color | json}}</tt>

          </form>
          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
        </file>
        <file name="protractor.js" type="protractor">
          it('should change state', function() {
            var color = element(by.binding('color'));

            expect(color.getText()).toContain('blue');

            element.all(by.model('color')).get(0).click();

            expect(color.getText()).toContain('red');
          });
        </file>
      </example>
   */
  'radio': radioInputType,

  /**
   * @ngdoc input
   * @name input[checkbox]
   *
   * @description
   * HTML checkbox.
   *
   * @param {string} ngModel Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
   * @param {string=} ngChange Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
      <example name="checkbox-input-directive">
        <file name="index.html">

         <form name="myForm" ng-controller="Ctrl">
           Value1: <input type="checkbox" ng-model="value1">

           Value2: <input type="checkbox" ng-model="value2"
                          ng-true-value="YES" ng-false-value="NO">

           <tt>value1 = {{value1}}</tt>

           <tt>value2 = {{value2}}</tt>

          </form>
        </file>
        <file name="protractor.js" type="protractor">
          it('should change state', function() {
            var value1 = element(by.binding('value1'));
            var value2 = element(by.binding('value2'));

            expect(value1.getText()).toContain('true');
            expect(value2.getText()).toContain('YES');

            element(by.model('value1')).click();
            element(by.model('value2')).click();

            expect(value1.getText()).toContain('false');
            expect(value2.getText()).toContain('NO');
          });
        </file>
      </example>
   */
  'checkbox': checkboxInputType,

  'hidden': noop,
  'button': noop,
  'submit': noop,
  'reset': noop,
  'file': noop
};

// A helper function to call $setValidity and return the value / undefined,
// a pattern that is repeated a lot in the input validation logic.
function validate(ctrl, validatorName, validity, value){
  ctrl.$setValidity(validatorName, validity);
  return validity ? value : undefined;
}

function addNativeHtml5Validators(ctrl, validatorName, element) {
  var validity = element.prop('validity');
  if (isObject(validity)) {
    var validator = function(value) {
      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
      // perform the required validation)
      if (!ctrl.$error[validatorName] && (validity.badInput || validity.customError ||
          validity.typeMismatch) && !validity.valueMissing) {
        ctrl.$setValidity(validatorName, false);
        return;
      }
      return value;
    };
    ctrl.$parsers.push(validator);
  }
}

function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  var validity = element.prop('validity');
  var placeholder = element[0].placeholder, noevent = {};

  // In composition mode, users are still inputing intermediate text buffer,
  // hold the listener until composition is done.
  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
  if (!$sniffer.android) {
    var composing = false;

    element.on('compositionstart', function(data) {
      composing = true;
    });

    element.on('compositionend', function() {
      composing = false;
      listener();
    });
  }

  var listener = function(ev) {
    if (composing) return;
    var value = element.val(),
        event = ev && ev.type;

    // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
    // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
    // IE also sends input events for other non-input-related things, (such as focusing on a
    // form control), so this change is not entirely enough to solve this.
    if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
      placeholder = element[0].placeholder;
      return;
    }

    // By default we will trim the value
    // If the attribute ng-trim exists we will avoid trimming
    // e.g. <input ng-model="foo" ng-trim="false">
    if (toBoolean(attr.ngTrim || 'T')) {
      value = trim(value);
    }

    if (ctrl.$viewValue !== value ||
        // If the value is still empty/falsy, and there is no `required` error, run validators
        // again. This enables HTML5 constraint validation errors to affect Angular validation
        // even when the first character entered causes an error.
        (validity && value === '' && !validity.valueMissing)) {
      if (scope.$$phase) {
        ctrl.$setViewValue(value, event);
      } else {
        scope.$apply(function() {
          ctrl.$setViewValue(value, event);
        });
      }
    }
  };

  // Allow adding/overriding bound events
  if (ctrl.$options && ctrl.$options.updateOn) {
    // bind to user-defined events
    element.on(ctrl.$options.updateOn, listener);
  }

  // setup default events if requested
  if (!ctrl.$options || ctrl.$options.updateOnDefault) {
    // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
    // input event on backspace, delete or cut
    if ($sniffer.hasEvent('input')) {
      element.on('input', listener);
    } else {
      var timeout;

      var deferListener = function(ev) {
        if (!timeout) {
          timeout = $browser.defer(function() {
            listener(ev);
            timeout = null;
          });
        }
      };

      element.on('keydown', function(event) {
        var key = event.keyCode;

        // ignore
        //    command            modifiers                   arrows
        if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;

        deferListener(event);
      });

      // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
      if ($sniffer.hasEvent('paste')) {
        element.on('paste cut', deferListener);
      }
    }

    // if user paste into input using mouse on older browser
    // or form autocomplete on newer browser, we need "change" event to catch it
    element.on('change', listener);
  }

  ctrl.$render = function() {
    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
  };

  // pattern validator
  var pattern = attr.ngPattern,
      patternValidator,
      match;

  if (pattern) {
    var validateRegex = function(regexp, value) {
      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
    };
    match = pattern.match(/^\/(.*)\/([gim]*)$/);
    if (match) {
      pattern = new RegExp(match[1], match[2]);
      patternValidator = function(value) {
        return validateRegex(pattern, value);
      };
    } else {
      patternValidator = function(value) {
        var patternObj = scope.$eval(pattern);

        if (!patternObj || !patternObj.test) {
          throw minErr('ngPattern')('noregexp',
            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
            patternObj, startingTag(element));
        }
        return validateRegex(patternObj, value);
      };
    }

    ctrl.$formatters.push(patternValidator);
    ctrl.$parsers.push(patternValidator);
  }

  // min length validator
  if (attr.ngMinlength) {
    var minlength = int(attr.ngMinlength);
    var minLengthValidator = function(value) {
      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
    };

    ctrl.$parsers.push(minLengthValidator);
    ctrl.$formatters.push(minLengthValidator);
  }

  // max length validator
  if (attr.ngMaxlength) {
    var maxlength = int(attr.ngMaxlength);
    var maxLengthValidator = function(value) {
      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
    };

    ctrl.$parsers.push(maxLengthValidator);
    ctrl.$formatters.push(maxLengthValidator);
  }
}

function weekParser(isoWeek) {
   if(isDate(isoWeek)) {
      return isoWeek;
   }

   if(isString(isoWeek)) {
      WEEK_REGEXP.lastIndex = 0;
      var parts = WEEK_REGEXP.exec(isoWeek);
      if(parts) {
         var year = +parts[1],
            week = +parts[2],
            firstThurs = getFirstThursdayOfYear(year),
            addDays = (week - 1) * 7;
         return new Date(year, 0, firstThurs.getDate() + addDays);
      }
   }

   return NaN;
}

function createDateParser(regexp, mapping) {
   return function(iso) {
      var parts, map;

      if(isDate(iso)) {
         return iso;
      }

      if(isString(iso)) {
         regexp.lastIndex = 0;
         parts = regexp.exec(iso);

         if(parts) {
            parts.shift();
            map = { yyyy: 0, MM: 1, dd: 1, HH: 0, mm: 0 };

            forEach(parts, function(part, index) {
               if(index < mapping.length) {
                  map[mapping[index]] = +part;
               }
            });

            return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm);
         }
      }

      return NaN;
   };
}

function createDateInputType(type, regexp, parseDate, format) {
   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
      textInputType(scope, element, attr, ctrl, $sniffer, $browser);

      ctrl.$parsers.push(function(value) {
         if(ctrl.$isEmpty(value)) {
            ctrl.$setValidity(type, true);
            return null;
         }

         if(regexp.test(value)) {
            ctrl.$setValidity(type, true);
            return parseDate(value);
         }

         ctrl.$setValidity(type, false);
         return undefined;
      });

      ctrl.$formatters.push(function(value) {
         if(isDate(value)) {
            return $filter('date')(value, format);
         }
         return '';
      });

      if(attr.min) {
         var minValidator = function(value) {
            var valid = ctrl.$isEmpty(value) ||
               (parseDate(value) >= parseDate(attr.min));
            ctrl.$setValidity('min', valid);
            return valid ? value : undefined;
         };

         ctrl.$parsers.push(minValidator);
         ctrl.$formatters.push(minValidator);
      }

      if(attr.max) {
         var maxValidator = function(value) {
            var valid = ctrl.$isEmpty(value) ||
               (parseDate(value) <= parseDate(attr.max));
            ctrl.$setValidity('max', valid);
            return valid ? value : undefined;
         };

         ctrl.$parsers.push(maxValidator);
         ctrl.$formatters.push(maxValidator);
      }
   };
}

function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);

  ctrl.$parsers.push(function(value) {
    var empty = ctrl.$isEmpty(value);
    if (empty || NUMBER_REGEXP.test(value)) {
      ctrl.$setValidity('number', true);
      return value === '' ? null : (empty ? value : parseFloat(value));
    } else {
      ctrl.$setValidity('number', false);
      return undefined;
    }
  });

  addNativeHtml5Validators(ctrl, 'number', element);

  ctrl.$formatters.push(function(value) {
    return ctrl.$isEmpty(value) ? '' : '' + value;
  });

  if (attr.min) {
    var minValidator = function(value) {
      var min = parseFloat(attr.min);
      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
    };

    ctrl.$parsers.push(minValidator);
    ctrl.$formatters.push(minValidator);
  }

  if (attr.max) {
    var maxValidator = function(value) {
      var max = parseFloat(attr.max);
      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
    };

    ctrl.$parsers.push(maxValidator);
    ctrl.$formatters.push(maxValidator);
  }

  ctrl.$formatters.push(function(value) {
    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
  });
}

function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);

  var urlValidator = function(value) {
    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
  };

  ctrl.$formatters.push(urlValidator);
  ctrl.$parsers.push(urlValidator);
}

function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);

  var emailValidator = function(value) {
    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
  };

  ctrl.$formatters.push(emailValidator);
  ctrl.$parsers.push(emailValidator);
}

function radioInputType(scope, element, attr, ctrl) {
  // make the name unique, if not defined
  if (isUndefined(attr.name)) {
    element.attr('name', nextUid());
  }

  var listener = function(ev) {
    if (element[0].checked) {
      scope.$apply(function() {
        ctrl.$setViewValue(attr.value, ev && ev.type);
      });
    }
  };

  // Allow adding/overriding bound events
  if (ctrl.$options && ctrl.$options.updateOn) {
    // bind to user-defined events
    element.on(ctrl.$options.updateOn, listener);
  }

  if (!ctrl.$options || ctrl.$options.updateOnDefault) {
    element.on('click', listener);
  }

  ctrl.$render = function() {
    var value = attr.value;
    element[0].checked = (value == ctrl.$viewValue);
  };

  attr.$observe('value', ctrl.$render);
}

function checkboxInputType(scope, element, attr, ctrl) {
  var trueValue = attr.ngTrueValue,
      falseValue = attr.ngFalseValue;

  if (!isString(trueValue)) trueValue = true;
  if (!isString(falseValue)) falseValue = false;

  var listener = function(ev) {
    scope.$apply(function() {
      ctrl.$setViewValue(element[0].checked, ev && ev.type);
    });
  };

  // Allow adding/overriding bound events
  if (ctrl.$options && ctrl.$options.updateOn) {
    // bind to user-defined events
    element.on(ctrl.$options.updateOn, listener);
  }

  if (!ctrl.$options || ctrl.$options.updateOnDefault) {
    element.on('click', listener);
  }

  ctrl.$render = function() {
    element[0].checked = ctrl.$viewValue;
  };

  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
  ctrl.$isEmpty = function(value) {
    return value !== trueValue;
  };

  ctrl.$formatters.push(function(value) {
    return value === trueValue;
  });

  ctrl.$parsers.push(function(value) {
    return value ? trueValue : falseValue;
  });
}

/**
 * @ngdoc directive
 * @name textarea
 * @restrict E
 *
 * @description
 * HTML textarea element control with angular data-binding. The data-binding and validation
 * properties of this element are exactly the same as those of the
 * {@link ng.directive:input input element}.
 *
 * @param {string} ngModel Assignable angular expression to data-bind to.
 * @param {string=} name Property name of the form under which the control is published.
 * @param {string=} required Sets `required` validation error key if the value is not entered.
 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
 *    `required` when you want to data-bind to the `required` attribute.
 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
 *    minlength.
 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
 *    maxlength.
 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
 *    patterns defined as scope expressions.
 * @param {string=} ngChange Angular expression to be executed when input changes due to user
 *    interaction with the input element.
 */

/**
 * @ngdoc directive
 * @name input
 * @restrict E
 *
 * @description
 * HTML input element control with angular data-binding. Input control follows HTML5 input types
 * and polyfills the HTML5 validation behavior for older browsers.
 *
 * @param {string} ngModel Assignable angular expression to data-bind to.
 * @param {string=} name Property name of the form under which the control is published.
 * @param {string=} required Sets `required` validation error key if the value is not entered.
 * @param {boolean=} ngRequired Sets `required` attribute if set to true
 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
 *    minlength.
 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
 *    maxlength.
 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
 *    patterns defined as scope expressions.
 * @param {string=} ngChange Angular expression to be executed when input changes due to user
 *    interaction with the input element.
 *
 * @example
    <example name="input-directive">
      <file name="index.html">

         <form name="myForm">
           User name: <input type="text" name="userName" ng-model="user.name" required>

             Required!

           Last name: <input type="text" name="lastName" ng-model="user.last"
             ng-minlength="3" ng-maxlength="10">

             Too short!

             Too long!

         </form>

         <tt>user = {{user}}</tt>

         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt>

         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt>

         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt>

         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt>

         <tt>myForm.$valid = {{myForm.$valid}}</tt>

         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt>

         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt>

      </file>
      <file name="protractor.js" type="protractor">
        var user = element(by.binding('{{user}}'));
        var userNameValid = element(by.binding('myForm.userName.$valid'));
        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
        var lastNameError = element(by.binding('myForm.lastName.$error'));
        var formValid = element(by.binding('myForm.$valid'));
        var userNameInput = element(by.model('user.name'));
        var userLastInput = element(by.model('user.last'));

        it('should initialize to model', function() {
          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
          expect(userNameValid.getText()).toContain('true');
          expect(formValid.getText()).toContain('true');
        });

        it('should be invalid if empty when required', function() {
          userNameInput.clear();
          userNameInput.sendKeys('');

          expect(user.getText()).toContain('{"last":"visitor"}');
          expect(userNameValid.getText()).toContain('false');
          expect(formValid.getText()).toContain('false');
        });

        it('should be valid if empty when min length is set', function() {
          userLastInput.clear();
          userLastInput.sendKeys('');

          expect(user.getText()).toContain('{"name":"guest","last":""}');
          expect(lastNameValid.getText()).toContain('true');
          expect(formValid.getText()).toContain('true');
        });

        it('should be invalid if less than required min length', function() {
          userLastInput.clear();
          userLastInput.sendKeys('xx');

          expect(user.getText()).toContain('{"name":"guest"}');
          expect(lastNameValid.getText()).toContain('false');
          expect(lastNameError.getText()).toContain('minlength');
          expect(formValid.getText()).toContain('false');
        });

        it('should be invalid if longer than max length', function() {
          userLastInput.clear();
          userLastInput.sendKeys('some ridiculously long name');

          expect(user.getText()).toContain('{"name":"guest"}');
          expect(lastNameValid.getText()).toContain('false');
          expect(lastNameError.getText()).toContain('maxlength');
          expect(formValid.getText()).toContain('false');
        });
      </file>
    </example>
 */
var inputDirective = ['$browser', '$sniffer', '$filter', function($browser, $sniffer, $filter) {
  return {
    restrict: 'E',
    require: ['?ngModel'],
    link: function(scope, element, attr, ctrls) {
      if (ctrls[0]) {
        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
                                                            $browser, $filter);
      }
    }
  };
}];

var VALID_CLASS = 'ng-valid',
    INVALID_CLASS = 'ng-invalid',
    PRISTINE_CLASS = 'ng-pristine',
    DIRTY_CLASS = 'ng-dirty';

/**
 * @ngdoc type
 * @name ngModel.NgModelController
 *
 * @property {string} $viewValue Actual string value in the view.
 * @property {*} $modelValue The value in the model, that the control is bound to.
 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
       the control reads value from the DOM.  Each function is called, in turn, passing the value
       through to the next. The last return value is used to populate the model.
       Used to sanitize / convert the value as well as validation. For validation,
       the parsers should update the validity state using
       {@link ngModel.NgModelController#$setValidity $setValidity()},
       and return `undefined` for invalid values.

 *
 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
       the model value changes. Each function is called, in turn, passing the value through to the
       next. Used to format / convert values for display in the control and validation.
 *      ```js
 *      function formatter(value) {
 *        if (value) {
 *          return value.toUpperCase();
 *        }
 *      }
 *      ngModel.$formatters.push(formatter);
 *      ```
 *
 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
 *     view value has changed. It is called with no arguments, and its return value is ignored.
 *     This can be used in place of additional $watches against the model value.
 *
 * @property {Object} $error An object hash with all errors as keys.
 *
 * @property {boolean} $pristine True if user has not interacted with the control yet.
 * @property {boolean} $dirty True if user has already interacted with the control.
 * @property {boolean} $valid True if there is no error.
 * @property {boolean} $invalid True if at least one error on the control.
 *
 * @description
 *
 * `NgModelController` provides API for the `ng-model` directive. The controller contains
 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
 * purposefully does not contain any logic which deals with DOM rendering or listening to
 * DOM events. Such DOM related logic should be provided by other directives which make use of
 * `NgModelController` for data-binding.
 *
 * ## Custom Control Example
 * This example shows how to use `NgModelController` with a custom control to achieve
 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
 * collaborate together to achieve the desired result.
 *
 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
 * contents be edited in place by the user.  This will not work on older browsers.
 *
 * <example name="NgModelController" module="customControl">
    <file name="style.css">
      [contenteditable] {
        border: 1px solid black;
        background-color: white;
        min-height: 20px;
      }

      .ng-invalid {
        border: 1px solid red;
      }

    </file>
    <file name="script.js">
      angular.module('customControl', []).
        directive('contenteditable', function() {
          return {
            restrict: 'A', // only activate on element attribute
            require: '?ngModel', // get a hold of NgModelController
            link: function(scope, element, attrs, ngModel) {
              if(!ngModel) return; // do nothing if no ng-model

              // Specify how UI should be updated
              ngModel.$render = function() {
                element.html(ngModel.$viewValue || '');
              };

              // Listen for change events to enable binding
              element.on('blur keyup change', function() {
                scope.$apply(read);
              });
              read(); // initialize

              // Write data to the model
              function read() {
                var html = element.html();
                // When we clear the content editable the browser leaves a
 behind
                // If strip-br attribute is provided then we strip this out
                if( attrs.stripBr && html == '
' ) {
                  html = '';
                }
                ngModel.$setViewValue(html);
              }
            }
          };
        });
    </file>
    <file name="index.html">
      <form name="myForm">

Change me!

        Required!

       <textarea ng-model="userContent"></textarea>
      </form>
    </file>
    <file name="protractor.js" type="protractor">
    it('should data-bind and become invalid', function() {
      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
        // SafariDriver can't handle contenteditable
        // and Firefox driver can't clear contenteditables very well
        return;
      }
      var contentEditable = element(by.css('[contenteditable]'));
      var content = 'Change me!';

      expect(contentEditable.getText()).toEqual(content);

      contentEditable.clear();
      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
      expect(contentEditable.getText()).toEqual('');
      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
    });
    </file>
 * </example>
 *
 *
 */
var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout',
    function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout) {
  this.$viewValue = Number.NaN;
  this.$modelValue = Number.NaN;
  this.$parsers = [];
  this.$formatters = [];
  this.$viewChangeListeners = [];
  this.$pristine = true;
  this.$dirty = false;
  this.$valid = true;
  this.$invalid = false;
  this.$name = $attr.name;

  var ngModelGet = $parse($attr.ngModel),
      ngModelSet = ngModelGet.assign,
      pendingDebounce = null,
      ctrl = this;

  if (!ngModelSet) {
    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
        $attr.ngModel, startingTag($element));
  }

  /**
   * @ngdoc method
   * @name ngModel.NgModelController#$render
   *
   * @description
   * Called when the view needs to be updated. It is expected that the user of the ng-model
   * directive will implement this method.
   */
  this.$render = noop;

  /**
   * @ngdoc method
   * @name ngModel.NgModelController#$isEmpty
   *
   * @description
   * This is called when we need to determine if the value of the input is empty.
   *
   * For instance, the required directive does this to work out if the input has data or not.
   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
   *
   * You can override this for input directives whose concept of being empty is different to the
   * default. The `checkboxInputType` directive does this because in its case a value of `false`
   * implies empty.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is empty.
   */
  this.$isEmpty = function(value) {
    return isUndefined(value) || value === '' || value === null || value !== value;
  };

  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
      invalidCount = 0, // used to easily determine if we are valid
      $error = this.$error = {}; // keep invalid keys here

  // Setup initial state of the control
  $element.addClass(PRISTINE_CLASS);
  toggleValidCss(true);

  // convenience method for easy toggling of classes
  function toggleValidCss(isValid, validationErrorKey) {
    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
    $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
    $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
  }

  /**
   * @ngdoc method
   * @name ngModel.NgModelController#$setValidity
   *
   * @description
   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
   * does not notify form if given validator is already marked as invalid).
   *
   * This method should be called by validators - i.e. the parser or formatter functions.
   *
   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
   *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
   */
  this.$setValidity = function(validationErrorKey, isValid) {
    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
    // jshint -W018
    if ($error[validationErrorKey] === !isValid) return;
    // jshint +W018

    if (isValid) {
      if ($error[validationErrorKey]) invalidCount--;
      if (!invalidCount) {
        toggleValidCss(true);
        ctrl.$valid = true;
        ctrl.$invalid = false;
      }
    } else {
      toggleValidCss(false);
      ctrl.$invalid = true;
      ctrl.$valid = false;
      invalidCount++;
    }

    $error[validationErrorKey] = !isValid;
    toggleValidCss(isValid, validationErrorKey);

    parentForm.$setValidity(validationErrorKey, isValid, ctrl);
  };

  /**
   * @ngdoc method
   * @name ngModel.NgModelController#$setPristine
   *
   * @description
   * Sets the control to its pristine state.
   *
   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
   * state (ng-pristine class).
   */
  this.$setPristine = function () {
    ctrl.$dirty = false;
    ctrl.$pristine = true;
    $animate.removeClass($element, DIRTY_CLASS);
    $animate.addClass($element, PRISTINE_CLASS);
  };

  /**
   * @ngdoc method
   * @name ngModel.NgModelController#$cancelUpdate
   *
   * @description
   * Cancel an update and reset the input element's value to prevent an update to the `$viewValue`,
   * which may be caused by a pending debounced event or because the input is waiting for a some
   * future event.
   *
   * If you have an input that uses `ng-model-options` to set up debounced events or events such
   * as blur you can have a situation where there is a period when the value of the input element
   * is out of synch with the ngModel's `$viewValue`.
   *
   * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
   * programmatically before these debounced/future events have resolved/occurred, because Angular's
   * dirty checking mechanism is not able to tell whether the model has actually changed or not.
   *
   * The `$cancelUpdate()` method should be called before programmatically changing the model of an
   * input which may have such events pending. This is important in order to make sure that the
   * input field will be updated with the new model value and any pending operations are cancelled.
   *
   * <example name="ng-model-cancel-update" module="cancel-update-example">
   *   <file name="app.js">
   *     angular.module('cancel-update-example', [])
   *
   *     .controller('CancelUpdateCtrl', function($scope) {
   *       $scope.resetWithCancel = function (e) {
   *         if (e.keyCode == 27) {
   *           $scope.myForm.myInput1.$cancelUpdate();
   *           $scope.myValue = '';
   *         }
   *       };
   *       $scope.resetWithoutCancel = function (e) {
   *         if (e.keyCode == 27) {
   *           $scope.myValue = '';
   *         }
   *       };
   *     });
   *   </file>
   *   <file name="index.html">
   *

   *
Try typing something in each input.  See that the model only updates when you
   *          blur off the input.
   *

   *
Now see what happens if you start typing then press the Escape key

   *
   *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
   *
With $cancelUpdate()

   *         <input name="myInput1" ng-model="myValue" ng-keydown="resetWithCancel($event)">

   *         myValue: "{{ myValue }}"
   *
   *
Without $cancelUpdate()

   *         <input name="myInput2" ng-model="myValue" ng-keydown="resetWithoutCancel($event)">

   *         myValue: "{{ myValue }}"
   *       </form>
   *

   *   </file>
   * </example>
   */
  this.$cancelUpdate = function() {
    $timeout.cancel(pendingDebounce);
    ctrl.$render();
  };

  // update the view value
  this.$$realSetViewValue = function(value) {
    ctrl.$viewValue = value;

    // change to dirty
    if (ctrl.$pristine) {
      ctrl.$dirty = true;
      ctrl.$pristine = false;
      $animate.removeClass($element, PRISTINE_CLASS);
      $animate.addClass($element, DIRTY_CLASS);
      parentForm.$setDirty();
    }

    forEach(ctrl.$parsers, function(fn) {
      value = fn(value);
    });

    if (ctrl.$modelValue !== value) {
      ctrl.$modelValue = value;
      ngModelSet($scope, value);
      forEach(ctrl.$viewChangeListeners, function(listener) {
        try {
          listener();
        } catch(e) {
          $exceptionHandler(e);
        }
      });
    }
  };

  /**
   * @ngdoc method
   * @name ngModel.NgModelController#$setViewValue
   *
   * @description
   * Update the view value.
   *
   * This method should be called when the view value changes, typically from within a DOM event handler.
   * For example {@link ng.directive:input input} and
   * {@link ng.directive:select select} directives call it.
   *
   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
   *
   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
   *
   * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
   * directive is used with a custom debounce for this particular event.
   *
   * Note that calling this function does not trigger a `$digest`.
   *
   * @param {string} value Value from the view.
   * @param {string} trigger Event that triggered the update.
   */
  this.$setViewValue = function(value, trigger) {
    var debounceDelay = ctrl.$options && (isObject(ctrl.$options.debounce)
        ? (ctrl.$options.debounce[trigger] || ctrl.$options.debounce['default'] || 0)
        : ctrl.$options.debounce) || 0;

    $timeout.cancel(pendingDebounce);
    if (debounceDelay) {
      pendingDebounce = $timeout(function() {
        ctrl.$$realSetViewValue(value);
      }, debounceDelay);
    } else {
      ctrl.$$realSetViewValue(value);
    }
  };

  // model -> value
  $scope.$watch(function ngModelWatch() {
    var value = ngModelGet($scope);

    // if scope model value and ngModel value are out of sync
    if (ctrl.$modelValue !== value) {

      var formatters = ctrl.$formatters,
          idx = formatters.length;

      ctrl.$modelValue = value;
      while(idx--) {
        value = formatters[idx](value);
      }

      if (ctrl.$viewValue !== value) {
        ctrl.$viewValue = value;
        ctrl.$render();
      }
    }

    return value;
  });
}];

/**
 * @ngdoc directive
 * @name ngModel
 *
 * @element input
 *
 * @description
 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
 * property on the scope using {@link ngModel.NgModelController NgModelController},
 * which is created and exposed by this directive.
 *
 * `ngModel` is responsible for:
 *
 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
 *   require.
 * - Providing validation behavior (i.e. required, number, email, url).
 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
 * - Registering the control with its parent {@link ng.directive:form form}.
 *
 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
 * current scope. If the property doesn't already exist on this scope, it will be created
 * implicitly and added to the scope.
 *
 * For best practices on using `ngModel`, see:
 *
 *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
 *
 * For basic examples, how to use `ngModel`, see:
 *
 *  - {@link ng.directive:input input}
 *    - {@link input[text] text}
 *    - {@link input[checkbox] checkbox}
 *    - {@link input[radio] radio}
 *    - {@link input[number] number}
 *    - {@link input[email] email}
 *    - {@link input[url] url}
 *    - {@link input[date] date}
 *    - {@link input[dateTimeLocal] dateTimeLocal}
 *    - {@link input[time] time}
 *    - {@link input[month] month}
 *    - {@link input[week] week}
 *  - {@link ng.directive:select select}
 *  - {@link ng.directive:textarea textarea}
 *
 * # CSS classes
 * The following CSS classes are added and removed on the associated input/select/textarea element
 * depending on the validity of the model.
 *
 *  - `ng-valid` is set if the model is valid.
 *  - `ng-invalid` is set if the model is invalid.
 *  - `ng-pristine` is set if the model is pristine.
 *  - `ng-dirty` is set if the model is dirty.
 *
 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
 *
 * ## Animation Hooks
 *
 * Animations within models are triggered when any of the associated CSS classes are added and removed
 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
 * The animations that are triggered within ngModel are similar to how they work in ngClass and
 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
 *
 * The following example shows a simple way to utilize CSS transitions to style an input element
 * that has been rendered as invalid after it has been validated:
 *
 *

 * //be sure to include ngAnimate as a module to hook into more
 * //advanced animations
 * .my-input {
 *   transition:0.5s linear all;
 *   background: white;
 * }
 * .my-input.ng-invalid {
 *   background: red;
 *   color:white;
 * }
 *

 *
 * @example
 * <example deps="angular-animate.js" animations="true" fixBase="true">
     <file name="index.html">

       Update input to see transitions when valid/invalid.
       Integer is a valid value.
       <form name="testForm" ng-controller="Ctrl">
         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
       </form>
     </file>
 * </example>
 */
var ngModelDirective = function() {
  return {
    require: ['ngModel', '^?form', '^?ngModelOptions'],
    controller: NgModelController,
    link: function(scope, element, attr, ctrls) {
      // notify others, especially parent forms

      var modelCtrl = ctrls[0],
          formCtrl = ctrls[1] || nullFormCtrl;

      formCtrl.$addControl(modelCtrl);

      // Pass the ng-model-options to the ng-model controller
      if ( ctrls[2] ) {
        modelCtrl.$options = ctrls[2].$options;
      }

      scope.$on('$destroy', function() {
        formCtrl.$removeControl(modelCtrl);
      });
    }
  };
};

/**
 * @ngdoc directive
 * @name ngChange
 *
 * @description
 * Evaluate the given expression when the user changes the input.
 * The expression is evaluated immediately, unlike the JavaScript onchange event
 * which only triggers at the end of a change (usually, when the user leaves the
 * form element or presses the return key).
 * The expression is not evaluated when the value change is coming from the model.
 *
 * Note, this directive requires `ngModel` to be present.
 *
 * @element input
 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
 * in input value.
 *
 * @example
 * <example name="ngChange-directive">
 *   <file name="index.html">
 *
 *

 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
 *       Confirmed

 *       <tt>debug = {{confirmed}}</tt>

 *       <tt>counter = {{counter}}</tt>

 *

 *   </file>
 *   <file name="protractor.js" type="protractor">
 *     var counter = element(by.binding('counter'));
 *     var debug = element(by.binding('confirmed'));
 *
 *     it('should evaluate the expression if changing from view', function() {
 *       expect(counter.getText()).toContain('0');
 *
 *       element(by.id('ng-change-example1')).click();
 *
 *       expect(counter.getText()).toContain('1');
 *       expect(debug.getText()).toContain('true');
 *     });
 *
 *     it('should not evaluate the expression if changing from model', function() {
 *       element(by.id('ng-change-example2')).click();

 *       expect(counter.getText()).toContain('0');
 *       expect(debug.getText()).toContain('true');
 *     });
 *   </file>
 * </example>
 */
var ngChangeDirective = valueFn({
  require: 'ngModel',
  link: function(scope, element, attr, ctrl) {
    ctrl.$viewChangeListeners.push(function() {
      scope.$eval(attr.ngChange);
    });
  }
});

var requiredDirective = function() {
  return {
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;
      attr.required = true; // force truthy in case we are on non input element

      var validator = function(value) {
        if (attr.required && ctrl.$isEmpty(value)) {
          ctrl.$setValidity('required', false);
          return;
        } else {
          ctrl.$setValidity('required', true);
          return value;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('required', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
};

/**
 * @ngdoc directive
 * @name ngList
 *
 * @description
 * Text input that converts between a delimited string and an array of strings. The delimiter
 * can be a fixed string (by default a comma) or a regular expression.
 *
 * @element input
 * @param {string=} ngList optional delimiter that should be used to split the value. If
 *   specified in form `/something/` then the value will be converted into a regular expression.
 *
 * @example
    <example name="ngList-directive">
      <file name="index.html">

       <form name="myForm" ng-controller="Ctrl">
         List: <input name="namesInput" ng-model="names" ng-list required>

           Required!

         <tt>names = {{names}}</tt>

         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt>

         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt>

         <tt>myForm.$valid = {{myForm.$valid}}</tt>

         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt>

        </form>
      </file>
      <file name="protractor.js" type="protractor">
        var listInput = element(by.model('names'));
        var names = element(by.binding('{{names}}'));
        var valid = element(by.binding('myForm.namesInput.$valid'));
        var error = element(by.css('span.error'));

        it('should initialize to model', function() {
          expect(names.getText()).toContain('["igor","misko","vojta"]');
          expect(valid.getText()).toContain('true');
          expect(error.getCssValue('display')).toBe('none');
        });

        it('should be invalid if empty', function() {
          listInput.clear();
          listInput.sendKeys('');

          expect(names.getText()).toContain('');
          expect(valid.getText()).toContain('false');
          expect(error.getCssValue('display')).not.toBe('none');        });
      </file>
    </example>
 */
var ngListDirective = function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attr, ctrl) {
      var match = /\/(.*)\//.exec(attr.ngList),
          separator = match && new RegExp(match[1]) || attr.ngList || ',';

      var parse = function(viewValue) {
        // If the viewValue is invalid (say required but empty) it will be `undefined`
        if (isUndefined(viewValue)) return;

        var list = [];

        if (viewValue) {
          forEach(viewValue.split(separator), function(value) {
            if (value) list.push(trim(value));
          });
        }

        return list;
      };

      ctrl.$parsers.push(parse);
      ctrl.$formatters.push(function(value) {
        if (isArray(value)) {
          return value.join(', ');
        }

        return undefined;
      });

      // Override the standard $isEmpty because an empty array means the input is empty.
      ctrl.$isEmpty = function(value) {
        return !value || !value.length;
      };
    }
  };
};

var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
/**
 * @ngdoc directive
 * @name ngValue
 *
 * @description
 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
 * that when the element is selected, the `ngModel` of that element is set to the
 * bound value.
 *
 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
 * shown below.
 *
 * @element input
 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
 *   of the `input` element
 *
 * @example
    <example name="ngValue-directive">
      <file name="index.html">

        <form ng-controller="Ctrl">

Which is your favorite?

              {{name}}
              <input type="radio"
                     ng-model="my.favorite"
                     ng-value="name"
                     id="{{name}}"
                     name="favorite">

You chose {{my.favorite}}

        </form>
      </file>
      <file name="protractor.js" type="protractor">
        var favorite = element(by.binding('my.favorite'));

        it('should initialize to model', function() {
          expect(favorite.getText()).toContain('unicorns');
        });
        it('should bind the values to the inputs', function() {
          element.all(by.model('my.favorite')).get(0).click();
          expect(favorite.getText()).toContain('pizza');
        });
      </file>
    </example>
 */
var ngValueDirective = function() {
  return {
    priority: 100,
    compile: function(tpl, tplAttr) {
      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
        return function ngValueConstantLink(scope, elm, attr) {
          attr.$set('value', scope.$eval(attr.ngValue));
        };
      } else {
        return function ngValueLink(scope, elm, attr) {
          scope.$watch(attr.ngValue, function valueWatchAction(value) {
            attr.$set('value', value);
          });
        };
      }
    }
  };
};

/**
 * @ngdoc directive
 * @name ngModelOptions
 *
 * @description
 * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
 * events that will trigger a model update and/or a debouncing delay so that the actual update only
 * takes place when a timer expires; this timer will be reset after another change takes place.
 *
 * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
 * be different then the value in the actual model. This means that if you update the model you
 * should also invoke {@link ngModel.NgModelController `$cancelUpdate`} on the relevant input field in
 * order to make sure it is synchronized with the model and that any debounced action is canceled.
 *
 * The easiest way to reference the control's {@link ngModel.NgModelController `$cancelUpdate`}
 * method is by making sure the input is placed inside a form that has a `name` attribute. This is
 * important because `form` controllers are published to the related scope under the name in their
 * `name` attribute.
 *
 * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
 *   - `updateOn`: string specifying which event should be the input bound to. You can set several
 *     events using an space delimited list. There is a special event called `default` that
 *     matches the default events belonging of the control.
 *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
 *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
 *     custom value for each event. For example:
 *     `ngModelOptions="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
 *
 * @example

  The following example shows how to override immediate updates. Changes on the inputs within the
  form will update the model only when the control loses focus (blur event). If `escape` key is
  pressed while the input field is focused, the value is reset to the value in the current model.

  <example name="ngModelOptions-directive-blur">
    <file name="index.html">

        <form name="userForm">
          Name:
          <input type="text" name="userName"
                 ng-model="user.name"
                 ng-model-options="{ updateOn: 'blur' }"
                 ng-keyup="cancel($event)" />

          Other data:
          <input type="text" ng-model="user.data" />

        </form>

user.name =

    </file>
    <file name="app.js">
      function Ctrl($scope) {
        $scope.user = { name: 'say', data: '' };

        $scope.cancel = function (e) {
          if (e.keyCode == 27) {
            $scope.userForm.userName.$cancelUpdate();
          }
        };
      }
    </file>
    <file name="protractor.js" type="protractor">
      var model = element(by.binding('user.name'));
      var input = element(by.model('user.name'));
      var other = element(by.model('user.data'));

      it('should allow custom events', function() {
        input.sendKeys(' hello');
        expect(model.getText()).toEqual('say');
        other.click();
        expect(model.getText()).toEqual('say hello');
      });

      it('should $cancelUpdate when model changes', function() {
        input.sendKeys(' hello');
        expect(input.getAttribute('value')).toEqual('say hello');
        input.sendKeys(protractor.Key.ESCAPE);
        expect(input.getAttribute('value')).toEqual('say');
        other.click();
        expect(model.getText()).toEqual('say');
      });
    </file>
  </example>

  This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
  If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.

  <example name="ngModelOptions-directive-debounce">
    <file name="index.html">

        <form name="userForm">
          Name:
          <input type="text" name="userName"
                 ng-model="user.name"
                 ng-model-options="{ debounce: 1000 }" />
          <button ng-click="userForm.userName.$cancelUpdate(); user.name=''">Clear</button>

        </form>

user.name =

    </file>
    <file name="app.js">
      function Ctrl($scope) {
        $scope.user = { name: 'say' };
      }
    </file>
  </example>
 */
var ngModelOptionsDirective = function() {
  return {
    controller: ['$scope', '$attrs', function($scope, $attrs) {
      var that = this;
      this.$options = $scope.$eval($attrs.ngModelOptions);
      // Allow adding/overriding bound events
      if (this.$options.updateOn) {
        this.$options.updateOnDefault = false;
        // extract "default" pseudo-event from list of events that can trigger a model update
        this.$options.updateOn = this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
          that.$options.updateOnDefault = true;
          return ' ';
        });
      } else {
        this.$options.updateOnDefault = true;
      }
    }]
  };
};


text:
title: Node PDX 2016 Bike Ride, Photos, and More
author: Adron Hall
date: 2016-06-29 10:25
template: article.jade
---
Node PDX, at least for me, kicked off Saturday morning before the conference. This involved the Geek Train, which as always was a great ride. After returning everyone went off for the evening and I prepared more for the conference.

The following day involved Sunday conference setup, workshops, and the Node PDX bike ride. Here's a few photos of the ride and our break at Cup & Bar. In the next blog entry I'll have more pictures & videos of the talks coming up.

![Node PDX Bike Ride](nodepdx-bike-ride.jpg)

![Cup and Bar](cup-and-bar.jpg)

![Cup and Bar One](cup-and-bar-1.jpg)

![Cup and Bar Bikes](cup-and-bar-bikes.jpg)

![Cup and Bar Chats](cup-and-bar-chats.jpg)

redpajama_set_name: RedPajamaGithub


text:
package com.fedevela.core.asic.cpanel.pojos;

/**
 * Created by fvelazquez on 26/03/14.
 */
import java.io.Serializable;
import java.math.BigInteger;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "DMS_CUSTOMER_HOLIDAYS_VW", catalog = "", schema = "PROD")
@NamedQueries({
        @NamedQuery(name = "DmsCustomerHolidaysVw.findAll", query = "SELECT d FROM DmsCustomerHolidaysVw d"),
        @NamedQuery(name = "DmsCustomerHolidaysVw.findByIdCustomer", query = "SELECT d FROM DmsCustomerHolidaysVw d WHERE d.idCustomer = :idCustomer"),
        @NamedQuery(name = "DmsCustomerHolidaysVw.findByDescription", query = "SELECT d FROM DmsCustomerHolidaysVw d WHERE d.description = :description"),
        @NamedQuery(name = "DmsCustomerHolidaysVw.findByPeriodCount", query = "SELECT d FROM DmsCustomerHolidaysVw d WHERE d.periodCount = :periodCount")})
public class DmsCustomerHolidaysVw implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ID_CUSTOMER")
    private short idCustomer;
    @Basic(optional = false)
    @Column(name = "DESCRIPTION")
    private String description;
    @Column(name = "PERIOD_COUNT")
    private BigInteger periodCount;

    public DmsCustomerHolidaysVw() {
    }

    public short getIdCustomer() {
        return idCustomer;
    }

    public void setIdCustomer(short idCustomer) {
        this.idCustomer = idCustomer;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public BigInteger getPeriodCount() {
        return periodCount;
    }

    public void setPeriodCount(BigInteger periodCount) {
        this.periodCount = periodCount;
    }

}


text:
<?php
/**
 * This file is part of Webnium BEAR.JsonSchemaValidation
 *
 * URL: https://github.com/webnium/BEAR.JsonSchemaValidation/
 */

namespace Webnium\BEAR\JsonSchemaValidation\Interceptor;

use BEAR\Resource\ResourceObject;
use BEAR\Resource\Link;
use BEAR\Resource\Code;
use Ray\Aop\MethodInvocation;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\NamedArgsInterface;
use Ray\Di\Di\Inject;
use JsonSchema\Uri\UriRetriever;
use JsonSchema\Validator as JsonValidator;
use Webnium\BEAR\JsonSchemaValidation\Exception;

/**
 * Validator for BEAR ResourceObjects
 *
 */
class JsonSchemaValidator implements MethodInterceptor
{
    /** @var UriRetriever */
    private $retriever;

    /** @var JsonValidator */
    private $validator;

    /** @var NamedArgsInterface */
    private $namedArgs;

    /**
     * Inject NamedArgs
     *
     * @param NamedArgsInterface $namedArgs
     * @Inject
     */
    public function setNamedArgs(NamedArgsInterface $namedArgs)
    {
        $this->namedArgs = $namedArgs;
    }

    /**
     * Inject UriRetriever
     *
     * @param UriRetriever $retriever
     * @Inject
     */
    public function setRetriever(UriRetriever $retriever)
    {
        $this->retriever = $retriever;
    }

    /**
     * Inject Json Validator
     *
     * @param JsonValidator $validator
     * @Inject
     */
    public function setValidator(JsonValidator $validator)
    {
        $this->validator = $validator;
    }

    /**
     * {@inheritdoc}
     */
    public function invoke(MethodInvocation $invocation)
    {
        $ro = $invocation->getThis();

        if (!preg_match('/^on(.+)$/', $invocation->getMethod()->name, $matches)) {
            throw new Exception\InvalidBinding;
        }

        $method = strtolower($matches[1]);

        $schema = $this->retrieveSchemaForMethod($ro, $method);
        if ($schema === null) {
            return $invocation->proceed();
        }

        $this->validator->check((object)json_decode(json_encode($this->namedArgs->get($invocation))), $schema);

        if ($this->validator->isValid()) {
            return $invocation->proceed();
        }

        $ro->code = Code::BAD_REQUEST;
        $ro->body = ['errors' => $this->validator->getErrors()];

        return $ro;
    }

    /**
     * Retrieve schema for method
     *
     * @param ResourceObject $ro
     * @param string         $method
     *
     * @return stdClass|null schema for the method
     */
    private function retrieveSchemaForMethod(ResourceObject $ro, $method)
    {
        $schema = $this->retriever->retrieve($ro->links['describedBy'][Link::HREF]);
        if (empty($schema->links)) {
            return null;
        }

        $methodSchema = null;

        foreach ($schema->links as $link) {
            if ($link->rel !== 'self') {
                continue;
            }

            if (empty($link->method)) {
                $methodSchema = $link->schema;
                continue;
            }

            if (strtolower($link->method) === $method) {
                $methodSchema = $link->schema;
                break;
            }
        }

        return $methodSchema;
    }
}