struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jo...@apache.org
Subject [39/52] [abbrv] [partial] struts-examples git commit: Add new rest plugin and angularjs based example application with support for bean validation and multi language support
Date Mon, 05 Oct 2015 18:06:44 GMT
http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-aria.min.js.map
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-aria.min.js.map b/rest-angular/src/main/webapp/js/lib/angular/angular-aria.min.js.map
new file mode 100644
index 0000000..a3e785f
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-aria.min.js.map
@@ -0,0 +1,8 @@
+{
+"version":3,
+"file":"angular-aria.min.js",
+"lineCount":12,
+"mappings":"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",
+"sources":["angular-aria.js"],
+"names":["window","angular","undefined","module","provider","ngAriaModule","$AriaProvider","watchExpr","attrName","ariaAttr","negate","scope","elem","attr","ariaCamelName","$normalize","config","$watch","boolVal","ariaHidden","ariaChecked","ariaDisabled","ariaRequired","ariaInvalid","ariaMultiline","ariaValue","tabindex","bindKeypress","bindRoleForClick","this.config","newConfig","extend","$get","this.$get","key","$$watchExpr","directive","$aria","shouldAttachAttr","normalizedAttr","shouldAttachRole","role","nodeName","getShape","type","restrict","require","priority","compile","shape","pre","ngModel","$isEmpty","ngModel.$isEmpty","value","post","ngAriaWatchModelValue","$modelValue","getRadioReaction","needsTabIndex","ngAriaRadioReaction","newVal","$viewValue","ngAriaCheckboxReaction","needsAriaValuemin","hasOwnProperty","needsAriaValuemax","needsAriaValuenow","$observe","ngAriaValueMinReaction","ngAriaValueNowReaction","$validators","required","ngAriaRequiredWatch","$error","ngAriaR
 equiredReaction","ngAriaInvalidWatch","$invalid","ngAriaInvalidReaction","link","ngMessages","$parse","fn","ngClick","isNodeOneOf","nodeTypeArray","indexOf","nodeBlackList","ngKeypress","on","event","callback","$event","keyCode","which","$apply"]
+}

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.js
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.js b/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.js
new file mode 100644
index 0000000..1d85b4e
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.js
@@ -0,0 +1,321 @@
+/**
+ * @license AngularJS v1.4.5
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {'use strict';
+
+/**
+ * @ngdoc module
+ * @name ngCookies
+ * @description
+ *
+ * # ngCookies
+ *
+ * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
+ *
+ *
+ * <div doc-module-components="ngCookies"></div>
+ *
+ * See {@link ngCookies.$cookies `$cookies`} for usage.
+ */
+
+
+angular.module('ngCookies', ['ng']).
+  /**
+   * @ngdoc provider
+   * @name $cookiesProvider
+   * @description
+   * Use `$cookiesProvider` to change the default behavior of the {@link ngCookies.$cookies $cookies} service.
+   * */
+   provider('$cookies', [function $CookiesProvider() {
+    /**
+     * @ngdoc property
+     * @name $cookiesProvider#defaults
+     * @description
+     *
+     * Object containing default options to pass when setting cookies.
+     *
+     * The object may have following properties:
+     *
+     * - **path** - `{string}` - The cookie will be available only for this path and its
+     *   sub-paths. By default, this would be the URL that appears in your base tag.
+     * - **domain** - `{string}` - The cookie will be available only for this domain and
+     *   its sub-domains. For obvious security reasons the user agent will not accept the
+     *   cookie if the current domain is not a sub domain or equals to the requested domain.
+     * - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT"
+     *   or a Date object indicating the exact date/time this cookie will expire.
+     * - **secure** - `{boolean}` - The cookie will be available only in secured connection.
+     *
+     * Note: by default the address that appears in your `<base>` tag will be used as path.
+     * This is important so that cookies will be visible for all routes in case html5mode is enabled
+     *
+     **/
+    var defaults = this.defaults = {};
+
+    function calcOptions(options) {
+      return options ? angular.extend({}, defaults, options) : defaults;
+    }
+
+    /**
+     * @ngdoc service
+     * @name $cookies
+     *
+     * @description
+     * Provides read/write access to browser's cookies.
+     *
+     * <div class="alert alert-info">
+     * Up until Angular 1.3, `$cookies` exposed properties that represented the
+     * current browser cookie values. In version 1.4, this behavior has changed, and
+     * `$cookies` now provides a standard api of getters, setters etc.
+     * </div>
+     *
+     * Requires the {@link ngCookies `ngCookies`} module to be installed.
+     *
+     * @example
+     *
+     * ```js
+     * angular.module('cookiesExample', ['ngCookies'])
+     *   .controller('ExampleController', ['$cookies', function($cookies) {
+     *     // Retrieving a cookie
+     *     var favoriteCookie = $cookies.get('myFavorite');
+     *     // Setting a cookie
+     *     $cookies.put('myFavorite', 'oatmeal');
+     *   }]);
+     * ```
+     */
+    this.$get = ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) {
+      return {
+        /**
+         * @ngdoc method
+         * @name $cookies#get
+         *
+         * @description
+         * Returns the value of given cookie key
+         *
+         * @param {string} key Id to use for lookup.
+         * @returns {string} Raw cookie value.
+         */
+        get: function(key) {
+          return $$cookieReader()[key];
+        },
+
+        /**
+         * @ngdoc method
+         * @name $cookies#getObject
+         *
+         * @description
+         * Returns the deserialized value of given cookie key
+         *
+         * @param {string} key Id to use for lookup.
+         * @returns {Object} Deserialized cookie value.
+         */
+        getObject: function(key) {
+          var value = this.get(key);
+          return value ? angular.fromJson(value) : value;
+        },
+
+        /**
+         * @ngdoc method
+         * @name $cookies#getAll
+         *
+         * @description
+         * Returns a key value object with all the cookies
+         *
+         * @returns {Object} All cookies
+         */
+        getAll: function() {
+          return $$cookieReader();
+        },
+
+        /**
+         * @ngdoc method
+         * @name $cookies#put
+         *
+         * @description
+         * Sets a value for given cookie key
+         *
+         * @param {string} key Id for the `value`.
+         * @param {string} value Raw value to be stored.
+         * @param {Object=} options Options object.
+         *    See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
+         */
+        put: function(key, value, options) {
+          $$cookieWriter(key, value, calcOptions(options));
+        },
+
+        /**
+         * @ngdoc method
+         * @name $cookies#putObject
+         *
+         * @description
+         * Serializes and sets a value for given cookie key
+         *
+         * @param {string} key Id for the `value`.
+         * @param {Object} value Value to be stored.
+         * @param {Object=} options Options object.
+         *    See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
+         */
+        putObject: function(key, value, options) {
+          this.put(key, angular.toJson(value), options);
+        },
+
+        /**
+         * @ngdoc method
+         * @name $cookies#remove
+         *
+         * @description
+         * Remove given cookie
+         *
+         * @param {string} key Id of the key-value pair to delete.
+         * @param {Object=} options Options object.
+         *    See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
+         */
+        remove: function(key, options) {
+          $$cookieWriter(key, undefined, calcOptions(options));
+        }
+      };
+    }];
+  }]);
+
+angular.module('ngCookies').
+/**
+ * @ngdoc service
+ * @name $cookieStore
+ * @deprecated
+ * @requires $cookies
+ *
+ * @description
+ * Provides a key-value (string-object) storage, that is backed by session cookies.
+ * Objects put or retrieved from this storage are automatically serialized or
+ * deserialized by angular's toJson/fromJson.
+ *
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
+ *
+ * <div class="alert alert-danger">
+ * **Note:** The $cookieStore service is **deprecated**.
+ * Please use the {@link ngCookies.$cookies `$cookies`} service instead.
+ * </div>
+ *
+ * @example
+ *
+ * ```js
+ * angular.module('cookieStoreExample', ['ngCookies'])
+ *   .controller('ExampleController', ['$cookieStore', function($cookieStore) {
+ *     // Put cookie
+ *     $cookieStore.put('myFavorite','oatmeal');
+ *     // Get cookie
+ *     var favoriteCookie = $cookieStore.get('myFavorite');
+ *     // Removing a cookie
+ *     $cookieStore.remove('myFavorite');
+ *   }]);
+ * ```
+ */
+ factory('$cookieStore', ['$cookies', function($cookies) {
+
+    return {
+      /**
+       * @ngdoc method
+       * @name $cookieStore#get
+       *
+       * @description
+       * Returns the value of given cookie key
+       *
+       * @param {string} key Id to use for lookup.
+       * @returns {Object} Deserialized cookie value, undefined if the cookie does not exist.
+       */
+      get: function(key) {
+        return $cookies.getObject(key);
+      },
+
+      /**
+       * @ngdoc method
+       * @name $cookieStore#put
+       *
+       * @description
+       * Sets a value for given cookie key
+       *
+       * @param {string} key Id for the `value`.
+       * @param {Object} value Value to be stored.
+       */
+      put: function(key, value) {
+        $cookies.putObject(key, value);
+      },
+
+      /**
+       * @ngdoc method
+       * @name $cookieStore#remove
+       *
+       * @description
+       * Remove given cookie
+       *
+       * @param {string} key Id of the key-value pair to delete.
+       */
+      remove: function(key) {
+        $cookies.remove(key);
+      }
+    };
+
+  }]);
+
+/**
+ * @name $$cookieWriter
+ * @requires $document
+ *
+ * @description
+ * This is a private service for writing cookies
+ *
+ * @param {string} name Cookie name
+ * @param {string=} value Cookie value (if undefined, cookie will be deleted)
+ * @param {Object=} options Object with options that need to be stored for the cookie.
+ */
+function $$CookieWriter($document, $log, $browser) {
+  var cookiePath = $browser.baseHref();
+  var rawDocument = $document[0];
+
+  function buildCookieString(name, value, options) {
+    var path, expires;
+    options = options || {};
+    expires = options.expires;
+    path = angular.isDefined(options.path) ? options.path : cookiePath;
+    if (value === undefined) {
+      expires = 'Thu, 01 Jan 1970 00:00:00 GMT';
+      value = '';
+    }
+    if (angular.isString(expires)) {
+      expires = new Date(expires);
+    }
+
+    var str = encodeURIComponent(name) + '=' + encodeURIComponent(value);
+    str += path ? ';path=' + path : '';
+    str += options.domain ? ';domain=' + options.domain : '';
+    str += expires ? ';expires=' + expires.toUTCString() : '';
+    str += options.secure ? ';secure' : '';
+
+    // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
+    // - 300 cookies
+    // - 20 cookies per unique domain
+    // - 4096 bytes per cookie
+    var cookieLength = str.length + 1;
+    if (cookieLength > 4096) {
+      $log.warn("Cookie '" + name +
+        "' possibly not set or overflowed because it was too large (" +
+        cookieLength + " > 4096 bytes)!");
+    }
+
+    return str;
+  }
+
+  return function(name, value, options) {
+    rawDocument.cookie = buildCookieString(name, value, options);
+  };
+}
+
+$$CookieWriter.$inject = ['$document', '$log', '$browser'];
+
+angular.module('ngCookies').provider('$$cookieWriter', function $$CookieWriterProvider() {
+  this.$get = $$CookieWriter;
+});
+
+
+})(window, window.angular);

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js b/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js
new file mode 100644
index 0000000..181624c
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js
@@ -0,0 +1,9 @@
+/*
+ AngularJS v1.4.5
+ (c) 2010-2015 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(p,g,l){'use strict';function m(b,a,f){var c=f.baseHref(),k=b[0];return function(b,d,e){var f,h;e=e||{};h=e.expires;f=g.isDefined(e.path)?e.path:c;d===l&&(h="Thu, 01 Jan 1970 00:00:00 GMT",d="");g.isString(h)&&(h=new Date(h));d=encodeURIComponent(b)+"="+encodeURIComponent(d);d=d+(f?";path="+f:"")+(e.domain?";domain="+e.domain:"");d+=h?";expires="+h.toUTCString():"";d+=e.secure?";secure":"";e=d.length+1;4096<e&&a.warn("Cookie '"+b+"' possibly not set or overflowed because it was too large ("+
+e+" > 4096 bytes)!");k.cookie=d}}g.module("ngCookies",["ng"]).provider("$cookies",[function(){var b=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(a,f){return{get:function(c){return a()[c]},getObject:function(c){return(c=this.get(c))?g.fromJson(c):c},getAll:function(){return a()},put:function(c,a,n){f(c,a,n?g.extend({},b,n):b)},putObject:function(c,b,a){this.put(c,g.toJson(b),a)},remove:function(a,k){f(a,l,k?g.extend({},b,k):b)}}}]}]);g.module("ngCookies").factory("$cookieStore",
+["$cookies",function(b){return{get:function(a){return b.getObject(a)},put:function(a,f){b.putObject(a,f)},remove:function(a){b.remove(a)}}}]);m.$inject=["$document","$log","$browser"];g.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular);
+//# sourceMappingURL=angular-cookies.min.js.map

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js.map
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js.map b/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js.map
new file mode 100644
index 0000000..84e6a57
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-cookies.min.js.map
@@ -0,0 +1,8 @@
+{
+"version":3,
+"file":"angular-cookies.min.js",
+"lineCount":8,
+"mappings":"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",
+"sources":["angular-cookies.js"],
+"names":["window","angular","undefined","$$CookieWriter","$document","$log","$browser","cookiePath","baseHref","rawDocument","name","value","options","path","expires","isDefined","isString","Date","str","encodeURIComponent","domain","toUTCString","secure","cookieLength","length","warn","cookie","module","provider","$CookiesProvider","defaults","$get","$$cookieReader","$$cookieWriter","get","key","getObject","fromJson","getAll","put","extend","putObject","toJson","remove","factory","$cookies","$inject","$$CookieWriterProvider"]
+}

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-csp.css
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-csp.css b/rest-angular/src/main/webapp/js/lib/angular/angular-csp.css
new file mode 100644
index 0000000..f3cd926
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-csp.css
@@ -0,0 +1,21 @@
+/* Include this file in your html if you are using the CSP mode. */
+
+@charset "UTF-8";
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
+.ng-cloak, .x-ng-cloak,
+.ng-hide:not(.ng-hide-animate) {
+  display: none !important;
+}
+
+ng\:form {
+  display: block;
+}
+
+.ng-animate-shim {
+  visibility:hidden;
+}
+
+.ng-anchor {
+  position:absolute;
+}

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-loader.js
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-loader.js b/rest-angular/src/main/webapp/js/lib/angular/angular-loader.js
new file mode 100644
index 0000000..092d894
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-loader.js
@@ -0,0 +1,443 @@
+/**
+ * @license AngularJS v1.4.5
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+
+(function() {'use strict';
+    function isFunction(value) {return typeof value === 'function';};
+
+/**
+ * @description
+ *
+ * This object provides a utility for producing rich Error messages within
+ * Angular. It can be called as follows:
+ *
+ * var exampleMinErr = minErr('example');
+ * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
+ *
+ * The above creates an instance of minErr in the example namespace. The
+ * resulting error will have a namespaced error code of example.one.  The
+ * resulting error will replace {0} with the value of foo, and {1} with the
+ * value of bar. The object is not restricted in the number of arguments it can
+ * take.
+ *
+ * If fewer arguments are specified than necessary for interpolation, the extra
+ * interpolation markers will be preserved in the final string.
+ *
+ * Since data will be parsed statically during a build step, some restrictions
+ * are applied with respect to how minErr instances are created and called.
+ * Instances should have names of the form namespaceMinErr for a minErr created
+ * using minErr('namespace') . Error codes, namespaces and template strings
+ * should all be static strings, not variables or general expressions.
+ *
+ * @param {string} module The namespace to use for the new minErr instance.
+ * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
+ *   error from returned function, for cases when a particular type of error is useful.
+ * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
+ */
+
+function minErr(module, ErrorConstructor) {
+  ErrorConstructor = ErrorConstructor || Error;
+  return function() {
+    var SKIP_INDEXES = 2;
+
+    var templateArgs = arguments,
+      code = templateArgs[0],
+      message = '[' + (module ? module + ':' : '') + code + '] ',
+      template = templateArgs[1],
+      paramPrefix, i;
+
+    message += template.replace(/\{\d+\}/g, function(match) {
+      var index = +match.slice(1, -1),
+        shiftedIndex = index + SKIP_INDEXES;
+
+      if (shiftedIndex < templateArgs.length) {
+        return toDebugString(templateArgs[shiftedIndex]);
+      }
+
+      return match;
+    });
+
+    message += '\nhttp://errors.angularjs.org/1.4.5/' +
+      (module ? module + '/' : '') + code;
+
+    for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
+      message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
+        encodeURIComponent(toDebugString(templateArgs[i]));
+    }
+
+    return new ErrorConstructor(message);
+  };
+}
+
+/**
+ * @ngdoc type
+ * @name angular.Module
+ * @module ng
+ * @description
+ *
+ * Interface for configuring angular {@link angular.module modules}.
+ */
+
+function setupModuleLoader(window) {
+
+  var $injectorMinErr = minErr('$injector');
+  var ngMinErr = minErr('ng');
+
+  function ensure(obj, name, factory) {
+    return obj[name] || (obj[name] = factory());
+  }
+
+  var angular = ensure(window, 'angular', Object);
+
+  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
+  angular.$$minErr = angular.$$minErr || minErr;
+
+  return ensure(angular, 'module', function() {
+    /** @type {Object.<string, angular.Module>} */
+    var modules = {};
+
+    /**
+     * @ngdoc function
+     * @name angular.module
+     * @module ng
+     * @description
+     *
+     * The `angular.module` is a global place for creating, registering and retrieving Angular
+     * modules.
+     * All modules (angular core or 3rd party) that should be available to an application must be
+     * registered using this mechanism.
+     *
+     * Passing one argument retrieves an existing {@link angular.Module},
+     * whereas passing more than one argument creates a new {@link angular.Module}
+     *
+     *
+     * # Module
+     *
+     * A module is a collection of services, directives, controllers, filters, and configuration information.
+     * `angular.module` is used to configure the {@link auto.$injector $injector}.
+     *
+     * ```js
+     * // Create a new module
+     * var myModule = angular.module('myModule', []);
+     *
+     * // register a new service
+     * myModule.value('appName', 'MyCoolApp');
+     *
+     * // configure existing services inside initialization blocks.
+     * myModule.config(['$locationProvider', function($locationProvider) {
+     *   // Configure existing providers
+     *   $locationProvider.hashPrefix('!');
+     * }]);
+     * ```
+     *
+     * Then you can create an injector and load your modules like this:
+     *
+     * ```js
+     * var injector = angular.injector(['ng', 'myModule'])
+     * ```
+     *
+     * However it's more likely that you'll just use
+     * {@link ng.directive:ngApp ngApp} or
+     * {@link angular.bootstrap} to simplify this process for you.
+     *
+     * @param {!string} name The name of the module to create or retrieve.
+     * @param {!Array.<string>=} requires If specified then new module is being created. If
+     *        unspecified then the module is being retrieved for further configuration.
+     * @param {Function=} configFn Optional configuration function for the module. Same as
+     *        {@link angular.Module#config Module#config()}.
+     * @returns {module} new module with the {@link angular.Module} api.
+     */
+    return function module(name, requires, configFn) {
+      var assertNotHasOwnProperty = function(name, context) {
+        if (name === 'hasOwnProperty') {
+          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
+        }
+      };
+
+      assertNotHasOwnProperty(name, 'module');
+      if (requires && modules.hasOwnProperty(name)) {
+        modules[name] = null;
+      }
+      return ensure(modules, name, function() {
+        if (!requires) {
+          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
+             "the module name or forgot to load it. If registering a module ensure that you " +
+             "specify the dependencies as the second argument.", name);
+        }
+
+        /** @type {!Array.<Array.<*>>} */
+        var invokeQueue = [];
+
+        /** @type {!Array.<Function>} */
+        var configBlocks = [];
+
+        /** @type {!Array.<Function>} */
+        var runBlocks = [];
+
+        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
+
+        /** @type {angular.Module} */
+        var moduleInstance = {
+          // Private state
+          _invokeQueue: invokeQueue,
+          _configBlocks: configBlocks,
+          _runBlocks: runBlocks,
+
+          /**
+           * @ngdoc property
+           * @name angular.Module#requires
+           * @module ng
+           *
+           * @description
+           * Holds the list of modules which the injector will load before the current module is
+           * loaded.
+           */
+          requires: requires,
+
+          /**
+           * @ngdoc property
+           * @name angular.Module#name
+           * @module ng
+           *
+           * @description
+           * Name of the module.
+           */
+          name: name,
+
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#provider
+           * @module ng
+           * @param {string} name service name
+           * @param {Function} providerType Construction function for creating new instance of the
+           *                                service.
+           * @description
+           * See {@link auto.$provide#provider $provide.provider()}.
+           */
+          provider: invokeLaterAndSetModuleName('$provide', 'provider'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#factory
+           * @module ng
+           * @param {string} name service name
+           * @param {Function} providerFunction Function for creating new instance of the service.
+           * @description
+           * See {@link auto.$provide#factory $provide.factory()}.
+           */
+          factory: invokeLaterAndSetModuleName('$provide', 'factory'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#service
+           * @module ng
+           * @param {string} name service name
+           * @param {Function} constructor A constructor function that will be instantiated.
+           * @description
+           * See {@link auto.$provide#service $provide.service()}.
+           */
+          service: invokeLaterAndSetModuleName('$provide', 'service'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#value
+           * @module ng
+           * @param {string} name service name
+           * @param {*} object Service instance object.
+           * @description
+           * See {@link auto.$provide#value $provide.value()}.
+           */
+          value: invokeLater('$provide', 'value'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#constant
+           * @module ng
+           * @param {string} name constant name
+           * @param {*} object Constant value.
+           * @description
+           * Because the constant are fixed, they get applied before other provide methods.
+           * See {@link auto.$provide#constant $provide.constant()}.
+           */
+          constant: invokeLater('$provide', 'constant', 'unshift'),
+
+           /**
+           * @ngdoc method
+           * @name angular.Module#decorator
+           * @module ng
+           * @param {string} The name of the service to decorate.
+           * @param {Function} This function will be invoked when the service needs to be
+           *                                    instantiated and should return the decorated service instance.
+           * @description
+           * See {@link auto.$provide#decorator $provide.decorator()}.
+           */
+          decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#animation
+           * @module ng
+           * @param {string} name animation name
+           * @param {Function} animationFactory Factory function for creating new instance of an
+           *                                    animation.
+           * @description
+           *
+           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
+           *
+           *
+           * Defines an animation hook that can be later used with
+           * {@link $animate $animate} service and directives that use this service.
+           *
+           * ```js
+           * module.animation('.animation-name', function($inject1, $inject2) {
+           *   return {
+           *     eventName : function(element, done) {
+           *       //code to run the animation
+           *       //once complete, then run done()
+           *       return function cancellationFunction(element) {
+           *         //code to cancel the animation
+           *       }
+           *     }
+           *   }
+           * })
+           * ```
+           *
+           * See {@link ng.$animateProvider#register $animateProvider.register()} and
+           * {@link ngAnimate ngAnimate module} for more information.
+           */
+          animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#filter
+           * @module ng
+           * @param {string} name Filter name - this must be a valid angular expression identifier
+           * @param {Function} filterFactory Factory function for creating new instance of filter.
+           * @description
+           * See {@link ng.$filterProvider#register $filterProvider.register()}.
+           *
+           * <div class="alert alert-warning">
+           * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
+           * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
+           * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
+           * (`myapp_subsection_filterx`).
+           * </div>
+           */
+          filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#controller
+           * @module ng
+           * @param {string|Object} name Controller name, or an object map of controllers where the
+           *    keys are the names and the values are the constructors.
+           * @param {Function} constructor Controller constructor function.
+           * @description
+           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
+           */
+          controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#directive
+           * @module ng
+           * @param {string|Object} name Directive name, or an object map of directives where the
+           *    keys are the names and the values are the factories.
+           * @param {Function} directiveFactory Factory function for creating new instance of
+           * directives.
+           * @description
+           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
+           */
+          directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#config
+           * @module ng
+           * @param {Function} configFn Execute this function on module load. Useful for service
+           *    configuration.
+           * @description
+           * Use this method to register work which needs to be performed on module loading.
+           * For more about how to configure services, see
+           * {@link providers#provider-recipe Provider Recipe}.
+           */
+          config: config,
+
+          /**
+           * @ngdoc method
+           * @name angular.Module#run
+           * @module ng
+           * @param {Function} initializationFn Execute this function after injector creation.
+           *    Useful for application initialization.
+           * @description
+           * Use this method to register work which should be performed when the injector is done
+           * loading all modules.
+           */
+          run: function(block) {
+            runBlocks.push(block);
+            return this;
+          }
+        };
+
+        if (configFn) {
+          config(configFn);
+        }
+
+        return moduleInstance;
+
+        /**
+         * @param {string} provider
+         * @param {string} method
+         * @param {String=} insertMethod
+         * @returns {angular.Module}
+         */
+        function invokeLater(provider, method, insertMethod, queue) {
+          if (!queue) queue = invokeQueue;
+          return function() {
+            queue[insertMethod || 'push']([provider, method, arguments]);
+            return moduleInstance;
+          };
+        }
+
+        /**
+         * @param {string} provider
+         * @param {string} method
+         * @returns {angular.Module}
+         */
+        function invokeLaterAndSetModuleName(provider, method) {
+          return function(recipeName, factoryFunction) {
+            if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
+            invokeQueue.push([provider, method, arguments]);
+            return moduleInstance;
+          };
+        }
+      });
+    };
+  });
+
+}
+
+setupModuleLoader(window);
+})(window);
+
+/**
+ * Closure compiler type information
+ *
+ * @typedef { {
+ *   requires: !Array.<string>,
+ *   invokeQueue: !Array.<Array.<*>>,
+ *
+ *   service: function(string, Function):angular.Module,
+ *   factory: function(string, Function):angular.Module,
+ *   value: function(string, *):angular.Module,
+ *
+ *   filter: function(string, Function):angular.Module,
+ *
+ *   init: function(Function):angular.Module
+ * } }
+ */
+angular.Module;
+

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js b/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js
new file mode 100644
index 0000000..8a31855
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js
@@ -0,0 +1,10 @@
+/*
+ AngularJS v1.4.5
+ (c) 2010-2015 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(){'use strict';function d(b){return function(){var a=arguments[0],e;e="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.4.5/"+(b?b+"/":"")+a;for(a=1;a<arguments.length;a++){e=e+(1==a?"?":"&")+"p"+(a-1)+"=";var d=encodeURIComponent,c;c=arguments[a];c="function"==typeof c?c.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof c?"undefined":"string"!=typeof c?JSON.stringify(c):c;e+=d(c)}return Error(e)}}(function(b){function a(c,a,b){return c[a]||(c[a]=b())}var e=d("$injector"),n=d("ng");
+b=a(b,"angular",Object);b.$$minErr=b.$$minErr||d;return a(b,"module",function(){var c={};return function(b,d,h){if("hasOwnProperty"===b)throw n("badname","module");d&&c.hasOwnProperty(b)&&(c[b]=null);return a(c,b,function(){function c(a,b,d,e){e||(e=f);return function(){e[d||"push"]([a,b,arguments]);return g}}function a(c,e){return function(a,d){d&&"function"===typeof d&&(d.$$moduleName=b);f.push([c,e,arguments]);return g}}if(!d)throw e("nomod",b);var f=[],k=[],l=[],m=c("$injector","invoke","push",
+k),g={_invokeQueue:f,_configBlocks:k,_runBlocks:l,requires:d,name:b,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:c("$provide","value"),constant:c("$provide","constant","unshift"),decorator:a("$provide","decorator"),animation:a("$animateProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:m,run:function(a){l.push(a);return this}};h&&m(h);
+return g})}})})(window)})(window);
+//# sourceMappingURL=angular-loader.min.js.map

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js.map
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js.map b/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js.map
new file mode 100644
index 0000000..d59cf1c
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-loader.min.js.map
@@ -0,0 +1,8 @@
+{
+"version":3,
+"file":"angular-loader.min.js",
+"lineCount":9,
+"mappings":"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",
+"sources":["angular-loader.js"],
+"names":["minErr","setupModuleLoader","window","ensure","obj","name","factory","$injectorMinErr","ngMinErr","angular","Object","$$minErr","modules","module","requires","configFn","context","hasOwnProperty","invokeLater","provider","method","insertMethod","queue","invokeQueue","arguments","moduleInstance","invokeLaterAndSetModuleName","recipeName","factoryFunction","$$moduleName","push","configBlocks","runBlocks","config","_invokeQueue","_configBlocks","_runBlocks","service","value","constant","decorator","animation","filter","controller","directive","run","block"]
+}

http://git-wip-us.apache.org/repos/asf/struts-examples/blob/a183bf5c/rest-angular/src/main/webapp/js/lib/angular/angular-message-format.js
----------------------------------------------------------------------
diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-message-format.js b/rest-angular/src/main/webapp/js/lib/angular/angular-message-format.js
new file mode 100644
index 0000000..6f136ab
--- /dev/null
+++ b/rest-angular/src/main/webapp/js/lib/angular/angular-message-format.js
@@ -0,0 +1,980 @@
+/**
+ * @license AngularJS v1.4.5
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {'use strict';
+
+// NOTE: ADVANCED_OPTIMIZATIONS mode.
+//
+// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
+// constructs incompatible with that mode.
+
+var $interpolateMinErr = window['angular']['$interpolateMinErr'];
+
+var noop = window['angular']['noop'],
+    isFunction = window['angular']['isFunction'],
+    toJson = window['angular']['toJson'];
+
+function stringify(value) {
+  if (value == null /* null/undefined */) { return ''; }
+  switch (typeof value) {
+    case 'string':     return value;
+    case 'number':     return '' + value;
+    default:           return toJson(value);
+  }
+}
+
+// Convert an index into the string into line/column for use in error messages
+// As such, this doesn't have to be efficient.
+function indexToLineAndColumn(text, index) {
+  var lines = text.split(/\n/g);
+  for (var i=0; i < lines.length; i++) {
+    var line=lines[i];
+    if (index >= line.length) {
+      index -= line.length;
+    } else {
+      return { line: i + 1, column: index + 1 };
+    }
+  }
+}
+var PARSE_CACHE_FOR_TEXT_LITERALS = Object.create(null);
+
+function parseTextLiteral(text) {
+  var cachedFn = PARSE_CACHE_FOR_TEXT_LITERALS[text];
+  if (cachedFn != null) {
+    return cachedFn;
+  }
+  function parsedFn(context) { return text; }
+  parsedFn['$$watchDelegate'] = function watchDelegate(scope, listener, objectEquality) {
+    var unwatch = scope['$watch'](noop,
+        function textLiteralWatcher() {
+          if (isFunction(listener)) { listener.call(null, text, text, scope); }
+          unwatch();
+        },
+        objectEquality);
+    return unwatch;
+  };
+  PARSE_CACHE_FOR_TEXT_LITERALS[text] = parsedFn;
+  parsedFn['exp'] = text; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
+  parsedFn['expressions'] = []; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding.
+  return parsedFn;
+}
+
+function subtractOffset(expressionFn, offset) {
+  if (offset === 0) {
+    return expressionFn;
+  }
+  function minusOffset(value) {
+    return (value == void 0) ? value : value - offset;
+  }
+  function parsedFn(context) { return minusOffset(expressionFn(context)); }
+  var unwatch;
+  parsedFn['$$watchDelegate'] = function watchDelegate(scope, listener, objectEquality) {
+    unwatch = scope['$watch'](expressionFn,
+        function pluralExpressionWatchListener(newValue, oldValue) {
+          if (isFunction(listener)) { listener.call(null, minusOffset(newValue), minusOffset(oldValue), scope); }
+        },
+        objectEquality);
+    return unwatch;
+  };
+  return parsedFn;
+}
+
+// NOTE: ADVANCED_OPTIMIZATIONS mode.
+//
+// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
+// constructs incompatible with that mode.
+
+/* global $interpolateMinErr: false */
+/* global isFunction: false */
+/* global noop: false */
+
+/**
+ * @constructor
+ * @private
+ */
+function MessageSelectorBase(expressionFn, choices) {
+  var self = this;
+  this.expressionFn = expressionFn;
+  this.choices = choices;
+  if (choices["other"] === void 0) {
+    throw $interpolateMinErr('reqother', '“other” is a required option.');
+  }
+  this.parsedFn = function(context) { return self.getResult(context); };
+  this.parsedFn['$$watchDelegate'] = function $$watchDelegate(scope, listener, objectEquality) {
+    return self.watchDelegate(scope, listener, objectEquality);
+  };
+  this.parsedFn['exp'] = expressionFn['exp'];
+  this.parsedFn['expressions'] = expressionFn['expressions'];
+}
+
+MessageSelectorBase.prototype.getMessageFn = function getMessageFn(value) {
+  return this.choices[this.categorizeValue(value)];
+};
+
+MessageSelectorBase.prototype.getResult = function getResult(context) {
+  return this.getMessageFn(this.expressionFn(context))(context);
+};
+
+MessageSelectorBase.prototype.watchDelegate = function watchDelegate(scope, listener, objectEquality) {
+  var watchers = new MessageSelectorWatchers(this, scope, listener, objectEquality);
+  return function() { watchers.cancelWatch(); };
+};
+
+/**
+ * @constructor
+ * @private
+ */
+function MessageSelectorWatchers(msgSelector, scope, listener, objectEquality) {
+  var self = this;
+  this.scope = scope;
+  this.msgSelector = msgSelector;
+  this.listener = listener;
+  this.objectEquality = objectEquality;
+  this.lastMessage = void 0;
+  this.messageFnWatcher = noop;
+  var expressionFnListener = function(newValue, oldValue) { return self.expressionFnListener(newValue, oldValue); };
+  this.expressionFnWatcher = scope['$watch'](msgSelector.expressionFn, expressionFnListener, objectEquality);
+}
+
+MessageSelectorWatchers.prototype.expressionFnListener = function expressionFnListener(newValue, oldValue) {
+  var self = this;
+  this.messageFnWatcher();
+  var messageFnListener = function(newMessage, oldMessage) { return self.messageFnListener(newMessage, oldMessage); };
+  var messageFn = this.msgSelector.getMessageFn(newValue);
+  this.messageFnWatcher = this.scope['$watch'](messageFn, messageFnListener, this.objectEquality);
+};
+
+MessageSelectorWatchers.prototype.messageFnListener = function messageFnListener(newMessage, oldMessage) {
+  if (isFunction(this.listener)) {
+    this.listener.call(null, newMessage, newMessage === oldMessage ? newMessage : this.lastMessage, this.scope);
+  }
+  this.lastMessage = newMessage;
+};
+
+MessageSelectorWatchers.prototype.cancelWatch = function cancelWatch() {
+  this.expressionFnWatcher();
+  this.messageFnWatcher();
+};
+
+/**
+ * @constructor
+ * @extends MessageSelectorBase
+ * @private
+ */
+function SelectMessage(expressionFn, choices) {
+  MessageSelectorBase.call(this, expressionFn, choices);
+}
+
+function SelectMessageProto() {}
+SelectMessageProto.prototype = MessageSelectorBase.prototype;
+
+SelectMessage.prototype = new SelectMessageProto();
+SelectMessage.prototype.categorizeValue = function categorizeSelectValue(value) {
+  return (this.choices[value] !== void 0) ? value : "other";
+};
+
+/**
+ * @constructor
+ * @extends MessageSelectorBase
+ * @private
+ */
+function PluralMessage(expressionFn, choices, offset, pluralCat) {
+  MessageSelectorBase.call(this, expressionFn, choices);
+  this.offset = offset;
+  this.pluralCat = pluralCat;
+}
+
+function PluralMessageProto() {}
+PluralMessageProto.prototype = MessageSelectorBase.prototype;
+
+PluralMessage.prototype = new PluralMessageProto();
+PluralMessage.prototype.categorizeValue = function categorizePluralValue(value) {
+  if (isNaN(value)) {
+    return "other";
+  } else if (this.choices[value] !== void 0) {
+    return value;
+  } else {
+    var category = this.pluralCat(value - this.offset);
+    return (this.choices[category] !== void 0) ? category : "other";
+  }
+};
+
+// NOTE: ADVANCED_OPTIMIZATIONS mode.
+//
+// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
+// constructs incompatible with that mode.
+
+/* global $interpolateMinErr: false */
+/* global isFunction: false */
+/* global parseTextLiteral: false */
+
+/**
+ * @constructor
+ * @private
+ */
+function InterpolationParts(trustedContext, allOrNothing) {
+  this.trustedContext = trustedContext;
+  this.allOrNothing = allOrNothing;
+  this.textParts = [];
+  this.expressionFns = [];
+  this.expressionIndices = [];
+  this.partialText = '';
+  this.concatParts = null;
+}
+
+InterpolationParts.prototype.flushPartialText = function flushPartialText() {
+  if (this.partialText) {
+    if (this.concatParts == null) {
+      this.textParts.push(this.partialText);
+    } else {
+      this.textParts.push(this.concatParts.join(''));
+      this.concatParts = null;
+    }
+    this.partialText = '';
+  }
+};
+
+InterpolationParts.prototype.addText = function addText(text) {
+  if (text.length) {
+    if (!this.partialText) {
+      this.partialText = text;
+    } else if (this.concatParts) {
+      this.concatParts.push(text);
+    } else {
+      this.concatParts = [this.partialText, text];
+    }
+  }
+};
+
+InterpolationParts.prototype.addExpressionFn = function addExpressionFn(expressionFn) {
+  this.flushPartialText();
+  this.expressionIndices.push(this.textParts.length);
+  this.expressionFns.push(expressionFn);
+  this.textParts.push('');
+};
+
+InterpolationParts.prototype.getExpressionValues = function getExpressionValues(context) {
+  var expressionValues = new Array(this.expressionFns.length);
+  for (var i = 0; i < this.expressionFns.length; i++) {
+    expressionValues[i] = this.expressionFns[i](context);
+  }
+  return expressionValues;
+};
+
+InterpolationParts.prototype.getResult = function getResult(expressionValues) {
+  for (var i = 0; i < this.expressionIndices.length; i++) {
+    var expressionValue = expressionValues[i];
+    if (this.allOrNothing && expressionValue === void 0) return;
+    this.textParts[this.expressionIndices[i]] = expressionValue;
+  }
+  return this.textParts.join('');
+};
+
+
+InterpolationParts.prototype.toParsedFn = function toParsedFn(mustHaveExpression, originalText) {
+  var self = this;
+  this.flushPartialText();
+  if (mustHaveExpression && this.expressionFns.length === 0) {
+    return void 0;
+  }
+  if (this.textParts.length === 0) {
+    return parseTextLiteral('');
+  }
+  if (this.trustedContext && this.textParts.length > 1) {
+    $interpolateMinErr['throwNoconcat'](originalText);
+  }
+  if (this.expressionFns.length === 0) {
+    if (this.textParts.length != 1) { this.errorInParseLogic(); }
+    return parseTextLiteral(this.textParts[0]);
+  }
+  var parsedFn = function(context) {
+    return self.getResult(self.getExpressionValues(context));
+  };
+  parsedFn['$$watchDelegate'] = function $$watchDelegate(scope, listener, objectEquality) {
+    return self.watchDelegate(scope, listener, objectEquality);
+  };
+
+  parsedFn['exp'] = originalText; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
+  parsedFn['expressions'] = new Array(this.expressionFns.length); // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding.
+  for (var i = 0; i < this.expressionFns.length; i++) {
+    parsedFn['expressions'][i] = this.expressionFns[i]['exp'];
+  }
+
+  return parsedFn;
+};
+
+InterpolationParts.prototype.watchDelegate = function watchDelegate(scope, listener, objectEquality) {
+  var watcher = new InterpolationPartsWatcher(this, scope, listener, objectEquality);
+  return function() { watcher.cancelWatch(); };
+};
+
+function InterpolationPartsWatcher(interpolationParts, scope, listener, objectEquality) {
+  this.interpolationParts = interpolationParts;
+  this.scope = scope;
+  this.previousResult = (void 0);
+  this.listener = listener;
+  var self = this;
+  this.expressionFnsWatcher = scope['$watchGroup'](interpolationParts.expressionFns, function(newExpressionValues, oldExpressionValues) {
+    self.watchListener(newExpressionValues, oldExpressionValues);
+  });
+}
+
+InterpolationPartsWatcher.prototype.watchListener = function watchListener(newExpressionValues, oldExpressionValues) {
+  var result = this.interpolationParts.getResult(newExpressionValues);
+  if (isFunction(this.listener)) {
+    this.listener.call(null, result, newExpressionValues === oldExpressionValues ? result : this.previousResult, this.scope);
+  }
+  this.previousResult = result;
+};
+
+InterpolationPartsWatcher.prototype.cancelWatch = function cancelWatch() {
+  this.expressionFnsWatcher();
+};
+
+// NOTE: ADVANCED_OPTIMIZATIONS mode.
+//
+// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
+// constructs incompatible with that mode.
+
+/* global $interpolateMinErr: false */
+/* global indexToLineAndColumn: false */
+/* global InterpolationParts: false */
+/* global PluralMessage: false */
+/* global SelectMessage: false */
+/* global subtractOffset: false */
+
+// The params src and dst are exactly one of two types: NestedParserState or MessageFormatParser.
+// This function is fully optimized by V8. (inspect via IRHydra or --trace-deopt.)
+// The idea behind writing it this way is to avoid repeating oneself.  This is the ONE place where
+// the parser state that is saved/restored when parsing nested mustaches is specified.
+function copyNestedParserState(src, dst) {
+  dst.expressionFn = src.expressionFn;
+  dst.expressionMinusOffsetFn = src.expressionMinusOffsetFn;
+  dst.pluralOffset = src.pluralOffset;
+  dst.choices = src.choices;
+  dst.choiceKey = src.choiceKey;
+  dst.interpolationParts = src.interpolationParts;
+  dst.ruleChoiceKeyword = src.ruleChoiceKeyword;
+  dst.msgStartIndex = src.msgStartIndex;
+  dst.expressionStartIndex = src.expressionStartIndex;
+}
+
+function NestedParserState(parser) {
+  copyNestedParserState(parser, this);
+}
+
+/**
+ * @constructor
+ * @private
+ */
+function MessageFormatParser(text, startIndex, $parse, pluralCat, stringifier,
+                             mustHaveExpression, trustedContext, allOrNothing) {
+  this.text = text;
+  this.index = startIndex || 0;
+  this.$parse = $parse;
+  this.pluralCat = pluralCat;
+  this.stringifier = stringifier;
+  this.mustHaveExpression = !!mustHaveExpression;
+  this.trustedContext = trustedContext;
+  this.allOrNothing = !!allOrNothing;
+  this.expressionFn = null;
+  this.expressionMinusOffsetFn = null;
+  this.pluralOffset = null;
+  this.choices = null;
+  this.choiceKey = null;
+  this.interpolationParts = null;
+  this.msgStartIndex = null;
+  this.nestedStateStack = [];
+  this.parsedFn = null;
+  this.rule = null;
+  this.ruleStack = null;
+  this.ruleChoiceKeyword = null;
+  this.interpNestLevel = null;
+  this.expressionStartIndex = null;
+  this.stringStartIndex = null;
+  this.stringQuote = null;
+  this.stringInterestsRe = null;
+  this.angularOperatorStack = null;
+  this.textPart = null;
+}
+
+// preserve v8 optimization.
+var EMPTY_STATE = new NestedParserState(new MessageFormatParser(
+        /* text= */ '', /* startIndex= */ 0, /* $parse= */ null, /* pluralCat= */ null, /* stringifier= */ null,
+        /* mustHaveExpression= */ false, /* trustedContext= */ null, /* allOrNothing */ false));
+
+MessageFormatParser.prototype.pushState = function pushState() {
+  this.nestedStateStack.push(new NestedParserState(this));
+  copyNestedParserState(EMPTY_STATE, this);
+};
+
+MessageFormatParser.prototype.popState = function popState() {
+  if (this.nestedStateStack.length === 0) {
+    this.errorInParseLogic();
+  }
+  var previousState = this.nestedStateStack.pop();
+  copyNestedParserState(previousState, this);
+};
+
+// Oh my JavaScript!  Who knew you couldn't match a regex at a specific
+// location in a string but will always search forward?!
+// Apparently you'll be growing this ability via the sticky flag (y) in
+// ES6.  I'll just to work around you for now.
+MessageFormatParser.prototype.matchRe = function matchRe(re, search) {
+  re.lastIndex = this.index;
+  var match = re.exec(this.text);
+  if (match != null && (search === true || (match.index == this.index))) {
+    this.index = re.lastIndex;
+    return match;
+  }
+  return null;
+};
+
+MessageFormatParser.prototype.searchRe = function searchRe(re) {
+  return this.matchRe(re, true);
+};
+
+
+MessageFormatParser.prototype.consumeRe = function consumeRe(re) {
+  // Without the sticky flag, we can't use the .test() method to consume a
+  // match at the current index.  Instead, we'll use the slower .exec() method
+  // and verify match.index.
+  return !!this.matchRe(re);
+};
+
+// Run through our grammar avoiding deeply nested function call chains.
+MessageFormatParser.prototype.run = function run(initialRule) {
+  this.ruleStack = [initialRule];
+  do {
+    this.rule = this.ruleStack.pop();
+    while (this.rule) {
+      this.rule();
+    }
+    this.assertRuleOrNull(this.rule);
+  } while (this.ruleStack.length > 0);
+};
+
+MessageFormatParser.prototype.errorInParseLogic = function errorInParseLogic() {
+    throw $interpolateMinErr('logicbug',
+        'The messageformat parser has encountered an internal error.  Please file a github issue against the AngularJS project and provide this message text that triggers the bug.  Text: “{0}”',
+        this.text);
+};
+
+MessageFormatParser.prototype.assertRuleOrNull = function assertRuleOrNull(rule) {
+  if (rule === void 0) {
+    this.errorInParseLogic();
+  }
+};
+
+var NEXT_WORD_RE = /\s*(\w+)\s*/g;
+MessageFormatParser.prototype.errorExpecting = function errorExpecting() {
+  // What was wrong with the syntax? Unsupported type, missing comma, or something else?
+  var match = this.matchRe(NEXT_WORD_RE), position;
+  if (match == null) {
+    position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('reqarg',
+        'Expected one of “plural” or “select” at line {0}, column {1} of text “{2}”',
+        position.line, position.column, this.text);
+  }
+  var word = match[1];
+  if (word == "select" || word == "plural") {
+    position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('reqcomma',
+        'Expected a comma after the keyword “{0}” at line {1}, column {2} of text “{3}”',
+        word, position.line, position.column, this.text);
+  } else {
+    position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('unknarg',
+        'Unsupported keyword “{0}” at line {0}, column {1}. Only “plural” and “select” are currently supported.  Text: “{3}”',
+        word, position.line, position.column, this.text);
+  }
+};
+
+var STRING_START_RE = /['"]/g;
+MessageFormatParser.prototype.ruleString = function ruleString() {
+  var match = this.matchRe(STRING_START_RE);
+  if (match == null) {
+    var position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('wantstring',
+        'Expected the beginning of a string at line {0}, column {1} in text “{2}”',
+        position.line, position.column, this.text);
+  }
+  this.startStringAtMatch(match);
+};
+
+MessageFormatParser.prototype.startStringAtMatch = function startStringAtMatch(match) {
+  this.stringStartIndex = match.index;
+  this.stringQuote = match[0];
+  this.stringInterestsRe = this.stringQuote == "'" ? SQUOTED_STRING_INTEREST_RE : DQUOTED_STRING_INTEREST_RE;
+  this.rule = this.ruleInsideString;
+};
+
+var SQUOTED_STRING_INTEREST_RE = /\\(?:\\|'|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}|[0-7]{3}|\r\n|\n|[\s\S])|'/g;
+var DQUOTED_STRING_INTEREST_RE = /\\(?:\\|"|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}|[0-7]{3}|\r\n|\n|[\s\S])|"/g;
+MessageFormatParser.prototype.ruleInsideString = function ruleInsideString() {
+  var match = this.searchRe(this.stringInterestsRe);
+  if (match == null) {
+    var position = indexToLineAndColumn(this.text, this.stringStartIndex);
+    throw $interpolateMinErr('untermstr',
+        'The string beginning at line {0}, column {1} is unterminated in text “{2}”',
+        position.line, position.column, this.text);
+  }
+  var chars = match[0];
+  if (match == this.stringQuote) {
+    this.rule = null;
+  }
+};
+
+var PLURAL_OR_SELECT_ARG_TYPE_RE = /\s*(plural|select)\s*,\s*/g;
+MessageFormatParser.prototype.rulePluralOrSelect = function rulePluralOrSelect() {
+  var match = this.searchRe(PLURAL_OR_SELECT_ARG_TYPE_RE);
+  if (match == null) {
+    this.errorExpecting();
+  }
+  var argType = match[1];
+  switch (argType) {
+    case "plural": this.rule = this.rulePluralStyle; break;
+    case "select": this.rule = this.ruleSelectStyle; break;
+    default: this.errorInParseLogic();
+  }
+};
+
+MessageFormatParser.prototype.rulePluralStyle = function rulePluralStyle() {
+  this.choices = Object.create(null);
+  this.ruleChoiceKeyword = this.rulePluralValueOrKeyword;
+  this.rule = this.rulePluralOffset;
+};
+
+MessageFormatParser.prototype.ruleSelectStyle = function ruleSelectStyle() {
+  this.choices = Object.create(null);
+  this.ruleChoiceKeyword = this.ruleSelectKeyword;
+  this.rule = this.ruleSelectKeyword;
+};
+
+var NUMBER_RE = /[0]|(?:[1-9][0-9]*)/g;
+var PLURAL_OFFSET_RE = new RegExp("\\s*offset\\s*:\\s*(" + NUMBER_RE.source + ")", "g");
+
+MessageFormatParser.prototype.rulePluralOffset = function rulePluralOffset() {
+  var match = this.matchRe(PLURAL_OFFSET_RE);
+  this.pluralOffset = (match == null) ? 0 : parseInt(match[1], 10);
+  this.expressionMinusOffsetFn = subtractOffset(this.expressionFn, this.pluralOffset);
+  this.rule = this.rulePluralValueOrKeyword;
+};
+
+MessageFormatParser.prototype.assertChoiceKeyIsNew = function assertChoiceKeyIsNew(choiceKey, index) {
+  if (this.choices[choiceKey] !== void 0) {
+    var position = indexToLineAndColumn(this.text, index);
+    throw $interpolateMinErr('dupvalue',
+        'The choice “{0}” is specified more than once. Duplicate key is at line {1}, column {2} in text “{3}”',
+        choiceKey, position.line, position.column, this.text);
+  }
+};
+
+var SELECT_KEYWORD = /\s*(\w+)/g;
+MessageFormatParser.prototype.ruleSelectKeyword = function ruleSelectKeyword() {
+  var match = this.matchRe(SELECT_KEYWORD);
+  if (match == null) {
+    this.parsedFn = new SelectMessage(this.expressionFn, this.choices).parsedFn;
+    this.rule = null;
+    return;
+  }
+  this.choiceKey = match[1];
+  this.assertChoiceKeyIsNew(this.choiceKey, match.index);
+  this.rule = this.ruleMessageText;
+};
+
+var EXPLICIT_VALUE_OR_KEYWORD_RE = new RegExp("\\s*(?:(?:=(" + NUMBER_RE.source + "))|(\\w+))", "g");
+MessageFormatParser.prototype.rulePluralValueOrKeyword = function rulePluralValueOrKeyword() {
+  var match = this.matchRe(EXPLICIT_VALUE_OR_KEYWORD_RE);
+  if (match == null) {
+    this.parsedFn = new PluralMessage(this.expressionFn, this.choices, this.pluralOffset, this.pluralCat).parsedFn;
+    this.rule = null;
+    return;
+  }
+  if (match[1] != null) {
+    this.choiceKey = parseInt(match[1], 10);
+  } else {
+    this.choiceKey = match[2];
+  }
+  this.assertChoiceKeyIsNew(this.choiceKey, match.index);
+  this.rule = this.ruleMessageText;
+};
+
+var BRACE_OPEN_RE = /\s*{/g;
+var BRACE_CLOSE_RE = /}/g;
+MessageFormatParser.prototype.ruleMessageText = function ruleMessageText() {
+  if (!this.consumeRe(BRACE_OPEN_RE)) {
+    var position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('reqopenbrace',
+        'The plural choice “{0}” must be followed by a message in braces at line {1}, column {2} in text “{3}”',
+        this.choiceKey, position.line, position.column, this.text);
+  }
+  this.msgStartIndex = this.index;
+  this.interpolationParts = new InterpolationParts(this.trustedContext, this.allOrNothing);
+  this.rule = this.ruleInInterpolationOrMessageText;
+};
+
+// Note: Since "\" is used as an escape character, don't allow it to be part of the
+// startSymbol/endSymbol when I add the feature to allow them to be redefined.
+var INTERP_OR_END_MESSAGE_RE = /\\.|{{|}/g;
+var INTERP_OR_PLURALVALUE_OR_END_MESSAGE_RE = /\\.|{{|#|}/g;
+var ESCAPE_OR_MUSTACHE_BEGIN_RE = /\\.|{{/g;
+MessageFormatParser.prototype.advanceInInterpolationOrMessageText = function advanceInInterpolationOrMessageText() {
+  var currentIndex = this.index, match, re;
+  if (this.ruleChoiceKeyword == null) { // interpolation
+    match = this.searchRe(ESCAPE_OR_MUSTACHE_BEGIN_RE);
+    if (match == null) { // End of interpolation text.  Nothing more to process.
+      this.textPart = this.text.substring(currentIndex);
+      this.index = this.text.length;
+      return null;
+    }
+  } else {
+    match = this.searchRe(this.ruleChoiceKeyword == this.rulePluralValueOrKeyword ?
+                          INTERP_OR_PLURALVALUE_OR_END_MESSAGE_RE : INTERP_OR_END_MESSAGE_RE);
+    if (match == null) {
+      var position = indexToLineAndColumn(this.text, this.msgStartIndex);
+      throw $interpolateMinErr('reqendbrace',
+          'The plural/select choice “{0}” message starting at line {1}, column {2} does not have an ending closing brace. Text “{3}”',
+          this.choiceKey, position.line, position.column, this.text);
+    }
+  }
+  // match is non-null.
+  var token = match[0];
+  this.textPart = this.text.substring(currentIndex, match.index);
+  return token;
+};
+
+MessageFormatParser.prototype.ruleInInterpolationOrMessageText = function ruleInInterpolationOrMessageText() {
+  var currentIndex = this.index;
+  var token = this.advanceInInterpolationOrMessageText();
+  if (token == null) {
+    // End of interpolation text.  Nothing more to process.
+    this.index = this.text.length;
+    this.interpolationParts.addText(this.text.substring(currentIndex));
+    this.rule = null;
+    return;
+  }
+  if (token[0] == "\\") {
+    // unescape next character and continue
+    this.interpolationParts.addText(this.textPart + token[1]);
+    return;
+  }
+  this.interpolationParts.addText(this.textPart);
+  if (token == "{{") {
+    this.pushState();
+    this.ruleStack.push(this.ruleEndMustacheInInterpolationOrMessage);
+    this.rule = this.ruleEnteredMustache;
+  } else if (token == "}") {
+    this.choices[this.choiceKey] = this.interpolationParts.toParsedFn(/*mustHaveExpression=*/false, this.text);
+    this.rule = this.ruleChoiceKeyword;
+  } else if (token == "#") {
+    this.interpolationParts.addExpressionFn(this.expressionMinusOffsetFn);
+  } else {
+    this.errorInParseLogic();
+  }
+};
+
+MessageFormatParser.prototype.ruleInterpolate = function ruleInterpolate() {
+  this.interpolationParts = new InterpolationParts(this.trustedContext, this.allOrNothing);
+  this.rule = this.ruleInInterpolation;
+};
+
+MessageFormatParser.prototype.ruleInInterpolation = function ruleInInterpolation() {
+  var currentIndex = this.index;
+  var match = this.searchRe(ESCAPE_OR_MUSTACHE_BEGIN_RE);
+  if (match == null) {
+    // End of interpolation text.  Nothing more to process.
+    this.index = this.text.length;
+    this.interpolationParts.addText(this.text.substring(currentIndex));
+    this.parsedFn = this.interpolationParts.toParsedFn(this.mustHaveExpression, this.text);
+    this.rule = null;
+    return;
+  }
+  var token = match[0];
+  if (token[0] == "\\") {
+    // unescape next character and continue
+    this.interpolationParts.addText(this.text.substring(currentIndex, match.index) + token[1]);
+    return;
+  }
+  this.interpolationParts.addText(this.text.substring(currentIndex, match.index));
+  this.pushState();
+  this.ruleStack.push(this.ruleInterpolationEndMustache);
+  this.rule = this.ruleEnteredMustache;
+};
+
+MessageFormatParser.prototype.ruleInterpolationEndMustache = function ruleInterpolationEndMustache() {
+  var expressionFn = this.parsedFn;
+  this.popState();
+  this.interpolationParts.addExpressionFn(expressionFn);
+  this.rule = this.ruleInInterpolation;
+};
+
+MessageFormatParser.prototype.ruleEnteredMustache = function ruleEnteredMustache() {
+  this.parsedFn = null;
+  this.ruleStack.push(this.ruleEndMustache);
+  this.rule = this.ruleAngularExpression;
+};
+
+MessageFormatParser.prototype.ruleEndMustacheInInterpolationOrMessage = function ruleEndMustacheInInterpolationOrMessage() {
+  var expressionFn = this.parsedFn;
+  this.popState();
+  this.interpolationParts.addExpressionFn(expressionFn);
+  this.rule = this.ruleInInterpolationOrMessageText;
+};
+
+
+
+var INTERP_END_RE = /\s*}}/g;
+MessageFormatParser.prototype.ruleEndMustache = function ruleEndMustache() {
+  var match = this.matchRe(INTERP_END_RE);
+  if (match == null) {
+    var position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('reqendinterp',
+        'Expecting end of interpolation symbol, “{0}”, at line {1}, column {2} in text “{3}”',
+        '}}', position.line, position.column, this.text);
+  }
+  if (this.parsedFn == null) {
+    // If we parsed a MessageFormat extension, (e.g. select/plural today, maybe more some other
+    // day), then the result *has* to be a string and those rules would have already set
+    // this.parsedFn.  If there was no MessageFormat extension, then there is no requirement to
+    // stringify the result and parsedFn isn't set.  We set it here.  While we could have set it
+    // unconditionally when exiting the Angular expression, I intend for us to not just replace
+    // $interpolate, but also to replace $parse in a future version (so ng-bind can work), and in
+    // such a case we do not want to unnecessarily stringify something if it's not going to be used
+    // in a string context.
+    this.parsedFn = this.$parse(this.expressionFn, this.stringifier);
+    this.parsedFn['exp'] = this.expressionFn['exp']; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
+    this.parsedFn['expressions'] = this.expressionFn['expressions']; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding.
+  }
+  this.rule = null;
+};
+
+MessageFormatParser.prototype.ruleAngularExpression = function ruleAngularExpression() {
+  this.angularOperatorStack = [];
+  this.expressionStartIndex = this.index;
+  this.rule = this.ruleInAngularExpression;
+};
+
+function getEndOperator(opBegin) {
+  switch (opBegin) {
+    case "{": return "}";
+    case "[": return "]";
+    case "(": return ")";
+    default: return null;
+  }
+}
+
+function getBeginOperator(opEnd) {
+  switch (opEnd) {
+    case "}": return "{";
+    case "]": return "[";
+    case ")": return "(";
+    default: return null;
+  }
+}
+
+// TODO(chirayu): The interpolation endSymbol must also be accounted for. It
+// just so happens that "}" is an operator so it's in the list below.  But we
+// should support any other type of start/end interpolation symbol.
+var INTERESTING_OPERATORS_RE = /[[\]{}()'",]/g;
+MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularExpression() {
+  var startIndex = this.index;
+  var match = this.searchRe(INTERESTING_OPERATORS_RE);
+  var position;
+  if (match == null) {
+    if (this.angularOperatorStack.length === 0) {
+      // This is the end of the Angular expression so this is actually a
+      // success.  Note that when inside an interpolation, this means we even
+      // consumed the closing interpolation symbols if they were curlies.  This
+      // is NOT an error at this point but will become an error further up the
+      // stack when the part that saw the opening curlies is unable to find the
+      // closing ones.
+      this.index = this.text.length;
+      this.expressionFn = this.$parse(this.text.substring(this.expressionStartIndex, this.index));
+      // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
+      this.expressionFn['exp'] = this.text.substring(this.expressionStartIndex, this.index);
+      this.expressionFn['expressions'] = this.expressionFn['expressions'];
+      this.rule = null;
+      return;
+    }
+    var innermostOperator = this.angularOperatorStack[0];
+    throw $interpolateMinErr('badexpr',
+        'Unexpected end of Angular expression.  Expecting operator “{0}” at the end of the text “{1}”',
+        this.getEndOperator(innermostOperator), this.text);
+  }
+  var operator = match[0];
+  if (operator == "'" || operator == '"') {
+    this.ruleStack.push(this.ruleInAngularExpression);
+    this.startStringAtMatch(match);
+    return;
+  }
+  if (operator == ",") {
+    if (this.trustedContext) {
+      position = indexToLineAndColumn(this.text, this.index);
+      throw $interpolateMinErr('unsafe',
+          'Use of select/plural MessageFormat syntax is currently disallowed in a secure context ({0}).  At line {1}, column {2} of text “{3}”',
+          this.trustedContext, position.line, position.column, this.text);
+    }
+    // only the top level comma has relevance.
+    if (this.angularOperatorStack.length === 0) {
+      // todo: does this need to be trimmed?
+      this.expressionFn = this.$parse(this.text.substring(this.expressionStartIndex, match.index));
+      // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
+      this.expressionFn['exp'] = this.text.substring(this.expressionStartIndex, match.index);
+      this.expressionFn['expressions'] = this.expressionFn['expressions'];
+      this.rule = null;
+      this.rule = this.rulePluralOrSelect;
+    }
+    return;
+  }
+  if (getEndOperator(operator) != null) {
+    this.angularOperatorStack.unshift(operator);
+    return;
+  }
+  var beginOperator = getBeginOperator(operator);
+  if (beginOperator == null) {
+    this.errorInParseLogic();
+  }
+  if (this.angularOperatorStack.length > 0) {
+    if (beginOperator == this.angularOperatorStack[0]) {
+      this.angularOperatorStack.shift();
+      return;
+    }
+    position = indexToLineAndColumn(this.text, this.index);
+    throw $interpolateMinErr('badexpr',
+        'Unexpected operator “{0}” at line {1}, column {2} in text. Was expecting “{3}”. Text: “{4}”',
+        operator, position.line, position.column, getEndOperator(this.angularOperatorStack[0]), this.text);
+  }
+  // We are trying to pop off the operator stack but there really isn't anything to pop off.
+  this.index = match.index;
+  this.expressionFn = this.$parse(this.text.substring(this.expressionStartIndex, this.index));
+  // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
+  this.expressionFn['exp'] = this.text.substring(this.expressionStartIndex, this.index);
+  this.expressionFn['expressions'] = this.expressionFn['expressions'];
+  this.rule = null;
+};
+
+// NOTE: ADVANCED_OPTIMIZATIONS mode.
+//
+// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
+// constructs incompatible with that mode.
+
+/* global $interpolateMinErr: false */
+/* global MessageFormatParser: false */
+/* global stringify: false */
+
+/**
+ * @ngdoc service
+ * @name $$messageFormat
+ *
+ * @description
+ * Angular internal service to recognize MessageFormat extensions in interpolation expressions.
+ * For more information, see:
+ * https://docs.google.com/a/google.com/document/d/1pbtW2yvtmFBikfRrJd8VAsabiFkKezmYZ_PbgdjQOVU/edit
+ *
+ * ## Example
+ *
+ * <example name="ngMessageFormat-example" module="msgFmtExample" deps="angular-message-format.min.js">
+ * <file name="index.html">
+ *   <div ng-controller="AppController">
+ *     <button ng-click="decreaseRecipients()" id="decreaseRecipients">decreaseRecipients</button><br>
+ *     <span>{{recipients.length, plural, offset:1
+ *             =0    {{{sender.name}} gave no gifts (\#=#)}
+ *             =1    {{{sender.name}} gave one gift to {{recipients[0].name}} (\#=#)}
+ *             one   {{{sender.name}} gave {{recipients[0].name}} and one other person a gift (\#=#)}
+ *             other {{{sender.name}} gave {{recipients[0].name}} and # other people a gift (\#=#)}
+ *           }}</span>
+ *   </div>
+ * </file>
+ *
+ * <file name="script.js">
+ *   function Person(name, gender) {
+ *     this.name = name;
+ *     this.gender = gender;
+ *   }
+ *
+ *   var alice   = new Person("Alice", "female"),
+ *       bob     = new Person("Bob", "male"),
+ *       charlie = new Person("Charlie", "male"),
+ *       harry   = new Person("Harry Potter", "male");
+ *
+ *   angular.module('msgFmtExample', ['ngMessageFormat'])
+ *     .controller('AppController', ['$scope', function($scope) {
+ *         $scope.recipients = [alice, bob, charlie];
+ *         $scope.sender = harry;
+ *         $scope.decreaseRecipients = function() {
+ *           --$scope.recipients.length;
+ *         };
+ *       }]);
+ * </file>
+ *
+ * <file name="protractor.js" type="protractor">
+ *   describe('MessageFormat plural', function() {
+ *     it('should pluralize initial values', function() {
+ *       var messageElem = element(by.binding('recipients.length')), decreaseRecipientsBtn = element(by.id('decreaseRecipients'));
+ *       expect(messageElem.getText()).toEqual('Harry Potter gave Alice and 2 other people a gift (#=2)');
+ *       decreaseRecipientsBtn.click();
+ *       expect(messageElem.getText()).toEqual('Harry Potter gave Alice and one other person a gift (#=1)');
+ *       decreaseRecipientsBtn.click();
+ *       expect(messageElem.getText()).toEqual('Harry Potter gave one gift to Alice (#=0)');
+ *       decreaseRecipientsBtn.click();
+ *       expect(messageElem.getText()).toEqual('Harry Potter gave no gifts (#=-1)');
+ *     });
+ *   });
+ * </file>
+ * </example>
+ */
+var $$MessageFormatFactory = ['$parse', '$locale', '$sce', '$exceptionHandler', function $$messageFormat(
+                   $parse,   $locale,   $sce,   $exceptionHandler) {
+
+  function getStringifier(trustedContext, allOrNothing, text) {
+    return function stringifier(value) {
+      try {
+        value = trustedContext ? $sce['getTrusted'](trustedContext, value) : $sce['valueOf'](value);
+        return allOrNothing && (value === void 0) ? value : stringify(value);
+      } catch (err) {
+        $exceptionHandler($interpolateMinErr['interr'](text, err));
+      }
+    };
+  }
+
+  function interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
+    var stringifier = getStringifier(trustedContext, allOrNothing, text);
+    var parser = new MessageFormatParser(text, 0, $parse, $locale['pluralCat'], stringifier,
+                                         mustHaveExpression, trustedContext, allOrNothing);
+    parser.run(parser.ruleInterpolate);
+    return parser.parsedFn;
+  }
+
+  return {
+    'interpolate': interpolate
+  };
+}];
+
+var $$interpolateDecorator = ['$$messageFormat', '$delegate', function $$interpolateDecorator($$messageFormat, $interpolate) {
+  if ($interpolate['startSymbol']() != "{{" || $interpolate['endSymbol']() != "}}") {
+    throw $interpolateMinErr('nochgmustache', 'angular-message-format.js currently does not allow you to use custom start and end symbols for interpolation.');
+  }
+  var interpolate = $$messageFormat['interpolate'];
+  interpolate['startSymbol'] = $interpolate['startSymbol'];
+  interpolate['endSymbol'] = $interpolate['endSymbol'];
+  return interpolate;
+}];
+
+
+/**
+ * @ngdoc module
+ * @name ngMessageFormat
+ * @packageName angular-message-format
+ * @description
+ */
+var module = window['angular']['module']('ngMessageFormat', ['ng']);
+module['factory']('$$messageFormat', $$MessageFormatFactory);
+module['config'](['$provide', function($provide) {
+  $provide['decorator']('$interpolate', $$interpolateDecorator);
+}]);
+
+
+})(window, window.angular);


Mime
View raw message