    /**
     * General purpose inflector class that {@link #pluralize pluralizes}, {@link #singularize singularizes} and
     * {@link #ordinalize ordinalizes} words. Sample usage:
     *
     *     //turning singular words into plurals
     *     Ext.util.Inflector.pluralize('word'); //'words'
     *     Ext.util.Inflector.pluralize('person'); //'people'
     *     Ext.util.Inflector.pluralize('sheep'); //'sheep'
     *
     *     //turning plurals into singulars
     *     Ext.util.Inflector.singularize('words'); //'word'
     *     Ext.util.Inflector.singularize('people'); //'person'
     *     Ext.util.Inflector.singularize('sheep'); //'sheep'
     *
     *     //ordinalizing numbers
     *     Ext.util.Inflector.ordinalize(11); //"11th"
     *     Ext.util.Inflector.ordinalize(21); //"21st"
     *     Ext.util.Inflector.ordinalize(1043); //"1043rd"
     *
     * # Customization
     *
     * The Inflector comes with a default set of US English pluralization rules. These can be augmented with additional
     * rules if the default rules do not meet your application's requirements, or swapped out entirely for other languages.
     * Here is how we might add a rule that pluralizes "ox" to "oxen":
     *
     *     Ext.util.Inflector.plural(/^(ox)$/i, "$1en");
     *
     * Each rule consists of two items - a regular expression that matches one or more rules, and a replacement string. In
     * this case, the regular expression will only match the string "ox", and will replace that match with "oxen". Here's
     * how we could add the inverse rule:
     *
     *     Ext.util.Inflector.singular(/^(ox)en$/i, "$1");
     *
     * Note that the ox/oxen rules are present by default.
     */
    Ext.define('Ext.util.Inflector', {

        /* Begin Definitions */

        singleton: true,

        /* End Definitions */

        /**
         * @private
         * The registered plural tuples. Each item in the array should contain two items - the first must be a regular
         * expression that matchers the singular form of a word, the second must be a String that replaces the matched
         * part of the regular expression. This is managed by the {@link #plural} method.
         * @property {Array} plurals
         */
        plurals: [
            [(/(quiz)$/i),                "$1zes"  ],
            [(/^(ox)$/i),                 "$1en"   ],
            [(/([m|l])ouse$/i),           "$1ice"  ],
            [(/(matr|vert|ind)ix|ex$/i),  "$1ices" ],
            [(/(x|ch|ss|sh)$/i),          "$1es"   ],
            [(/([^aeiouy]|qu)y$/i),       "$1ies"  ],
            [(/(hive)$/i),                "$1s"    ],
            [(/(?:([^f])fe|([lr])f)$/i),  "$1$2ves"],
            [(/sis$/i),                   "ses"    ],
            [(/([ti])um$/i),              "$1a"    ],
            [(/(buffal|tomat|potat)o$/i), "$1oes"  ],
            [(/(bu)s$/i),                 "$1ses"  ],
            [(/(alias|status|sex)$/i),    "$1es"   ],
            [(/(octop|vir)us$/i),         "$1i"    ],
            [(/(ax|test)is$/i),           "$1es"   ],
            [(/^person$/),                "people" ],
            [(/^man$/),                   "men"    ],
            [(/^(child)$/),               "$1ren"  ],
            [(/s$/i),                     "s"      ],
            [(/$/),                       "s"      ]
        ],

        /**
         * @private
         * The set of registered singular matchers. Each item in the array should contain two items - the first must be a
         * regular expression that matches the plural form of a word, the second must be a String that replaces the
         * matched part of the regular expression. This is managed by the {@link #singular} method.
         * @property {Array} singulars
         */
        singulars: [
          [(/(quiz)zes$/i),                                                    "$1"     ],
          [(/(matr)ices$/i),                                                   "$1ix"   ],
          [(/(vert|ind)ices$/i),                                               "$1ex"   ],
          [(/^(ox)en/i),                                                       "$1"     ],
          [(/(alias|status)es$/i),                                             "$1"     ],
          [(/(octop|vir)i$/i),                                                 "$1us"   ],
          [(/(cris|ax|test)es$/i),                                             "$1is"   ],
          [(/(shoe)s$/i),                                                      "$1"     ],
          [(/(o)es$/i),                                                        "$1"     ],
          [(/(bus)es$/i),                                                      "$1"     ],
          [(/([m|l])ice$/i),                                                   "$1ouse" ],
          [(/(x|ch|ss|sh)es$/i),                                               "$1"     ],
          [(/(m)ovies$/i),                                                     "$1ovie" ],
          [(/(s)eries$/i),                                                     "$1eries"],
          [(/([^aeiouy]|qu)ies$/i),                                            "$1y"    ],
          [(/([lr])ves$/i),                                                    "$1f"    ],
          [(/(tive)s$/i),                                                      "$1"     ],
          [(/(hive)s$/i),                                                      "$1"     ],
          [(/([^f])ves$/i),                                                    "$1fe"   ],
          [(/(^analy)ses$/i),                                                  "$1sis"  ],
          [(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i), "$1$2sis"],
          [(/([ti])a$/i),                                                      "$1um"   ],
          [(/(n)ews$/i),                                                       "$1ews"  ],
          [(/people$/i),                                                       "person" ],
          [(/s$/i),                                                            ""       ]
        ],

        /**
         * @private
         * The registered uncountable words
         * @property {String[]} uncountable
         */
         uncountable: [
            "sheep",
            "fish",
            "series",
            "species",
            "money",
            "rice",
            "information",
            "equipment",
            "grass",
            "mud",
            "offspring",
            "deer",
            "means"
        ],

        /**
         * Adds a new singularization rule to the Inflector. See the intro docs for more information
         * @param {RegExp} matcher The matcher regex
         * @param {String} replacer The replacement string, which can reference matches from the matcher argument
         */
        singular: function(matcher, replacer) {
            this.singulars.unshift([matcher, replacer]);
        },

        /**
         * Adds a new pluralization rule to the Inflector. See the intro docs for more information
         * @param {RegExp} matcher The matcher regex
         * @param {String} replacer The replacement string, which can reference matches from the matcher argument
         */
        plural: function(matcher, replacer) {
            this.plurals.unshift([matcher, replacer]);
        },

        /**
         * Removes all registered singularization rules
         */
        clearSingulars: function() {
            this.singulars = [];
        },

        /**
         * Removes all registered pluralization rules
         */
        clearPlurals: function() {
            this.plurals = [];
        },

        /**
         * Returns true if the given word is transnumeral (the word is its own singular and plural form - e.g. sheep, fish)
         * @param {String} word The word to test
         * @return {Boolean} True if the word is transnumeral
         */
        isTransnumeral: function(word) {
            return Ext.Array.indexOf(this.uncountable, word) != -1;
        },

        /**
         * Returns the pluralized form of a word (e.g. Ext.util.Inflector.pluralize('word') returns 'words')
         * @param {String} word The word to pluralize
         * @return {String} The pluralized form of the word
         */
        pluralize: function(word) {
            if (this.isTransnumeral(word)) {
                return word;
            }

            var plurals = this.plurals,
                length  = plurals.length,
                tuple, regex, i;

            for (i = 0; i < length; i++) {
                tuple = plurals[i];
                regex = tuple[0];

                if (regex == word || (regex.test && regex.test(word))) {
                    return word.replace(regex, tuple[1]);
                }
            }

            return word;
        },

        /**
         * Returns the singularized form of a word (e.g. Ext.util.Inflector.singularize('words') returns 'word')
         * @param {String} word The word to singularize
         * @return {String} The singularized form of the word
         */
        singularize: function(word) {
            if (this.isTransnumeral(word)) {
                return word;
            }

            var singulars = this.singulars,
                length    = singulars.length,
                tuple, regex, i;

            for (i = 0; i < length; i++) {
                tuple = singulars[i];
                regex = tuple[0];

                if (regex == word || (regex.test && regex.test(word))) {
                    return word.replace(regex, tuple[1]);
                }
            }

            return word;
        },

        /**
         * Returns the correct {@link Ext.data.Model Model} name for a given string. Mostly used internally by the data
         * package
         * @param {String} word The word to classify
         * @return {String} The classified version of the word
         */
        classify: function(word) {
            return Ext.String.capitalize(this.singularize(word));
        },

        /**
         * Ordinalizes a given number by adding a prefix such as 'st', 'nd', 'rd' or 'th' based on the last digit of the
         * number. 21 -> 21st, 22 -> 22nd, 23 -> 23rd, 24 -> 24th etc
         * @param {Number} number The number to ordinalize
         * @return {String} The ordinalized number
         */
        ordinalize: function(number) {
            var parsed = parseInt(number, 10),
                mod10  = parsed % 10,
                mod100 = parsed % 100;

            //11 through 13 are a special case
            if (11 <= mod100 && mod100 <= 13) {
                return number + "th";
            } else {
                switch(mod10) {
                    case 1 : return number + "st";
                    case 2 : return number + "nd";
                    case 3 : return number + "rd";
                    default: return number + "th";
                }
            }
        }
    }, function() {
        //aside from the rules above, there are a number of words that have irregular pluralization so we add them here
        var irregulars = {
                alumnus: 'alumni',
                cactus : 'cacti',
                focus  : 'foci',
                nucleus: 'nuclei',
                radius: 'radii',
                stimulus: 'stimuli',
                ellipsis: 'ellipses',
                paralysis: 'paralyses',
                oasis: 'oases',
                appendix: 'appendices',
                index: 'indexes',
                beau: 'beaux',
                bureau: 'bureaux',
                tableau: 'tableaux',
                woman: 'women',
                child: 'children',
                man: 'men',
                corpus:	'corpora',
                criterion: 'criteria',
                curriculum:	'curricula',
                genus: 'genera',
                memorandum:	'memoranda',
                phenomenon:	'phenomena',
                foot: 'feet',
                goose: 'geese',
                tooth: 'teeth',
                antenna: 'antennae',
                formula: 'formulae',
                nebula: 'nebulae',
                vertebra: 'vertebrae',
                vita: 'vitae'
            },
            singular;

        for (singular in irregulars) {
            this.plural(singular, irregulars[singular]);
            this.singular(irregulars[singular], singular);
        }
    });