Вход Регистрация
Файл: ui/development-bundle/external/globalize.js
Строк: 1913
<?php
/*!
 * Globalize
 *
 * http://github.com/jquery/globalize
 *
 * Copyright Software Freedom Conservancy, Inc.
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */

(function( windowundefined ) {

var 
Globalize,
    
// private variables
    
regexHex,
    
regexInfinity,
    
regexParseFloat,
    
regexTrim,
    
// private JavaScript utility functions
    
arrayIndexOf,
    
endsWith,
    
extend,
    
isArray,
    
isFunction,
    
isObject,
    
startsWith,
    
trim,
    
truncate,
    
zeroPad,
    
// private Globalization utility functions
    
appendPreOrPostMatch,
    
expandFormat,
    
formatDate,
    
formatNumber,
    
getTokenRegExp,
    
getEra,
    
getEraYear,
    
parseExact,
    
parseNegativePattern;

// Global variable (Globalize) or CommonJS module (globalize)
Globalize = function( cultureSelector ) {
    return new 
Globalize.prototype.initcultureSelector );
};

if ( 
typeof require !== "undefined"
    
&& typeof exports !== "undefined"
    
&& typeof module !== "undefined" ) {
    
// Assume CommonJS
    
module.exports Globalize;
} else {
    
// Export as global variable
    
window.Globalize Globalize;
}

Globalize.cultures = {};

Globalize.prototype = {
    
constructorGlobalize,
    
init: function( cultureSelector ) {
        
this.cultures Globalize.cultures;
        
this.cultureSelector cultureSelector;

        return 
this;
    }
};
Globalize.prototype.init.prototype Globalize.prototype;

// 1.     When defining a culture, all fields are required except the ones stated as optional.
// 2.     Each culture should have a ".calendars" object with at least one calendar named "standard"
//         which serves as the default calendar in use by that culture.
// 3.     Each culture should have a ".calendar" object which is the current calendar being used,
//         it may be dynamically changed at any time to one of the calendars in ".calendars".
Globalize.cultures"default" ] = {
    
// A unique name for the culture in the form <language code>-<country/region code>
    
name"en",
    
// the name of the culture in the english language
    
englishName"English",
    
// the name of the culture in its own language
    
nativeName"English",
    
// whether the culture uses right-to-left text
    
isRTLfalse,
    
// "language" is used for so-called "specific" cultures.
    // For example, the culture "es-CL" means "Spanish, in Chili".
    // It represents the Spanish-speaking culture as it is in Chili,
    // which might have different formatting rules or even translations
    // than Spanish in Spain. A "neutral" culture is one that is not
    // specific to a region. For example, the culture "es" is the generic
    // Spanish culture, which may be a more generalized version of the language
    // that may or may not be what a specific culture expects.
    // For a specific culture like "es-CL", the "language" field refers to the
    // neutral, generic culture information for the language it is using.
    // This is not always a simple matter of the string before the dash.
    // For example, the "zh-Hans" culture is netural (Simplified Chinese).
    // And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage
    // field is "zh-CHS", not "zh".
    // This field should be used to navigate from a specific culture to it's
    // more general, neutral culture. If a culture is already as general as it
    // can get, the language may refer to itself.
    
language"en",
    
// numberFormat defines general number formatting rules, like the digits in
    // each grouping, the group separator, and how negative numbers are displayed.
    
numberFormat: {
        
// [negativePattern]
        // Note, numberFormat.pattern has no "positivePattern" unlike percent and currency,
        // but is still defined as an array for consistency with them.
        //   negativePattern: one of "(n)|-n|- n|n-|n -"
        
pattern: [ "-n" ],
        
// number of decimal places normally shown
        
decimals2,
        
// string that separates number groups, as in 1,000,000
        
","",",
        
// string that separates a number from the fractional portion, as in 1.99
        
"."".",
        
// array of numbers indicating the size of each number group.
        // TODO: more detailed description and example
        
groupSizes: [ ],
        
// symbol used for positive numbers
        
"+""+",
        
// symbol used for negative numbers
        
"-""-",
        
// symbol used for NaN (Not-A-Number)
        
NaN"NaN",
        
// symbol used for Negative Infinity
        
negativeInfinity"-Infinity",
        
// symbol used for Positive Infinity
        
positiveInfinity"Infinity",
        
percent: {
            
// [negativePattern, positivePattern]
            //   negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %"
            //   positivePattern: one of "n %|n%|%n|% n"
            
pattern: [ "-n %""n %" ],
            
// number of decimal places normally shown
            
decimals2,
            
// array of numbers indicating the size of each number group.
            // TODO: more detailed description and example
            
groupSizes: [ ],
            
// string that separates number groups, as in 1,000,000
            
","",",
            
// string that separates a number from the fractional portion, as in 1.99
            
"."".",
            
// symbol used to represent a percentage
            
symbol"%"
        
},
        
currency: {
            
// [negativePattern, positivePattern]
            //   negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)"
            //   positivePattern: one of "$n|n$|$ n|n $"
            
pattern: [ "($n)""$n],
            
// number of decimal places normally shown
            
decimals2,
            
// array of numbers indicating the size of each number group.
            // TODO: more detailed description and example
            
groupSizes: [ ],
            
// string that separates number groups, as in 1,000,000
            
","",",
            
// string that separates a number from the fractional portion, as in 1.99
            
"."".",
            
// symbol used to represent currency
            
symbol"$"
        
}
    },
    
// calendars defines all the possible calendars used by this culture.
    // There should be at least one defined with name "standard", and is the default
    // calendar used by the culture.
    // A calendar contains information about how dates are formatted, information about
    // the calendar's eras, a standard set of the date formats,
    // translations for day and month names, and if the calendar is not based on the Gregorian
    // calendar, conversion functions to and from the Gregorian calendar.
    
calendars: {
        
standard: {
            
// name that identifies the type of calendar this is
            
name"Gregorian_USEnglish",
            
// separator of parts of a date (e.g. "/" in 11/05/1955)
            
"/""/",
            
// separator of parts of a time (e.g. ":" in 05:44 PM)
            
":"":",
            
// the first day of the week (0 = Sunday, 1 = Monday, etc)
            
firstDay0,
            
days: {
                
// full day names
                
names: [ "Sunday""Monday""Tuesday""Wednesday""Thursday""Friday""Saturday" ],
                
// abbreviated day names
                
namesAbbr: [ "Sun""Mon""Tue""Wed""Thu""Fri""Sat" ],
                
// shortest day names
                
namesShort: [ "Su""Mo""Tu""We""Th""Fr""Sa" ]
            },
            
months: {
                
// full month names (13 months for lunar calendards -- 13th month should be "" if not lunar)
                
names: [ "January""February""March""April""May""June""July""August""September""October""November""December""" ],
                
// abbreviated month names
                
namesAbbr: [ "Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct""Nov""Dec""" ]
            },
            
// AM and PM designators in one of these forms:
            // The usual view, and the upper and lower case versions
            //   [ standard, lowercase, uppercase ]
            // The culture does not use AM or PM (likely all standard date formats use 24 hour time)
            //   null
            
AM: [ "AM""am""AM" ],
            
PM: [ "PM""pm""PM" ],
            
eras: [
                
// eras in reverse chronological order.
                // name: the name of the era in this culture (e.g. A.D., C.E.)
                // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era.
                // offset: offset in years from gregorian calendar
                
{
                    
"name""A.D.",
                    
"start"null,
                    
"offset"0
                
}
            ],
            
// when a two digit year is given, it will never be parsed as a four digit
            // year greater than this year (in the appropriate era for the culture)
            // Set it as a full year (e.g. 2029) or use an offset format starting from
            // the current year: "+19" would correspond to 2029 if the current year 2010.
            
twoDigitYearMax2029,
            
// set of predefined date and time patterns used by the culture
            // these represent the format someone in this culture would expect
            // to see given the portions of the date that are shown.
            
patterns: {
                
// short date pattern
                
d"M/d/yyyy",
                
// long date pattern
                
D"dddd, MMMM dd, yyyy",
                
// short time pattern
                
t"h:mm tt",
                
// long time pattern
                
T"h:mm:ss tt",
                
// long date, short time pattern
                
f"dddd, MMMM dd, yyyy h:mm tt",
                
// long date, long time pattern
                
F"dddd, MMMM dd, yyyy h:mm:ss tt",
                
// month/day pattern
                
M"MMMM dd",
                
// month/year pattern
                
Y"yyyy MMMM",
                
// S is a sortable format that does not vary by culture
                
S"yyyyu0027-u0027MMu0027-u0027ddu0027Tu0027HHu0027:u0027mmu0027:u0027ss"
            
}
            
// optional fields for each calendar:
            /*
            monthsGenitive:
                Same as months but used when the day preceeds the month.
                Omit if the culture has no genitive distinction in month names.
                For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx
            convert:
                Allows for the support of non-gregorian based calendars. This convert object is used to
                to convert a date to and from a gregorian calendar date to handle parsing and formatting.
                The two functions:
                    fromGregorian( date )
                        Given the date as a parameter, return an array with parts [ year, month, day ]
                        corresponding to the non-gregorian based year, month, and day for the calendar.
                    toGregorian( year, month, day )
                        Given the non-gregorian year, month, and day, return a new Date() object
                        set to the corresponding date in the gregorian calendar.
            */
        
}
    },
    
// For localized strings
    
messages: {}
};

Globalize.cultures"default" ].calendar Globalize.cultures"default" ].calendars.standard;

Globalize.cultures"en" ] = Globalize.cultures"default" ];

Globalize.cultureSelector "en";

//
// private variables
//

regexHex = /^0x[a-f0-9]+$/i;
regexInfinity = /^[+-]?infinity$/i;
regexParseFloat = /^[+-]?d*.?d*(e[+-]?d+)?$/;
regexTrim = /^s+|s+$/g;

//
// private JavaScript utility functions
//

arrayIndexOf = function( array, item ) {
    if ( array.
indexOf ) {
        return array.
indexOfitem );
    }
    for ( var 
0length = array.lengthlengthi++ ) {
        if ( array[
i] === item ) {
            return 
i;
        }
    }
    return -
1;
};

endsWith = function( valuepattern ) {
    return 
value.substrvalue.length pattern.length ) === pattern;
};

extend = function( deep ) {
    var 
optionsnamesrccopycopyIsArray, clone,
        
target arguments[0] || {},
        
1,
        
length arguments.length,
        
deep false;

    
// Handle a deep copy situation
    
if ( typeof target === "boolean" ) {
        
deep target;
        
target arguments[1] || {};
        
// skip the boolean and the target
        
2;
    }

    
// Handle case when target is a string or something (possible in deep copy)
    
if ( typeof target !== "object" && !isFunction(target) ) {
        
target = {};
    }

    for ( ; 
lengthi++ ) {
        
// Only deal with non-null/undefined values
        
if ( (options arguments]) != null ) {
            
// Extend the base object
            
for ( name in options ) {
                
src targetname ];
                
copy optionsname ];

                
// Prevent never-ending loop
                
if ( target === copy ) {
                    continue;
                }

                
// Recurse if we're merging plain objects or arrays
                
if ( deep && copy && ( isObject(copy) || (copyIsArray isArray(copy)) ) ) {
                    if ( 
copyIsArray ) {
                        
copyIsArray false;
                        clone = 
src && isArray(src) ? src : [];

                    } else {
                        clone = 
src && isObject(src) ? src : {};
                    }

                    
// Never move original objects, clone them
                    
targetname ] = extenddeep, clone, copy );

                
// Don't bring in undefined values
                
} else if ( copy !== undefined ) {
                    
targetname ] = copy;
                }
            }
        }
    }

    
// Return the modified object
    
return target;
};

isArray = Array.isArray || function( obj ) {
    return 
Object.prototype.toString.callobj ) === "[object Array]";
};

isFunction = function( obj ) {
    return 
Object.prototype.toString.callobj ) === "[object Function]"
}

isObject = function( obj ) {
    return 
Object.prototype.toString.callobj ) === "[object Object]";
};

startsWith = function( valuepattern ) {
    return 
value.indexOfpattern ) === 0;
};

trim = function( value ) {
    return ( 
value "" ).replaceregexTrim"" );
};

truncate = function( value ) {
    return 
value 0;
};

zeroPad = function( strcountleft ) {
    var 
l;
    for ( 
str.lengthcount+= ) {
        
str = ( left ? ("0" str) : (str "0") );
    }
    return 
str;
};

//
// private Globalization utility functions
//

appendPreOrPostMatch = function( preMatchstrings ) {
    
// appends pre- and post- token match strings while removing escaped characters.
    // Returns a single quote count which is used to determine if the token occurs
    // in a string literal.
    
var quoteCount 0,
        
escaped false;
    for ( var 
0il preMatch.lengthili++ ) {
        var 
preMatch.charAt);
        switch ( 
) {
            case 
"'":
                if ( 
escaped ) {
                    
strings.push"'" );
                }
                else {
                    
quoteCount++;
                }
                
escaped false;
                break;
            case 
"\":
                if ( escaped ) {
                    strings.push( "
\" );
                }
                escaped = !escaped;
                break;
            default:
                strings.push( c );
                escaped = false;
                break;
        }
    }
    return quoteCount;
};

expandFormat = function( cal, format ) {
    // expands unspecified or single character date formats into the full pattern.
    format = format || "
F";
    var pattern,
        patterns = cal.patterns,
        len = format.length;
    if ( len === 1 ) {
        pattern = patterns[ format ];
        if ( !pattern ) {
            throw "
Invalid date format string '" + format + "'.";
        }
        format = pattern;
    }
    else if ( len === 2 && format.charAt(0) === "
%" ) {
        // %X escape format -- intended as a custom format string that is only one character, not a built-in format.
        format = format.charAt( 1 );
    }
    return format;
};

formatDate = function( value, format, culture ) {
    var cal = culture.calendar,
        convert = cal.convert;

    if ( !format || !format.length || format === "
i" ) {
        var ret;
        if ( culture && culture.name.length ) {
            if ( convert ) {
                // non-gregorian calendar, so we cannot use built-in toLocaleString()
                ret = formatDate( value, cal.patterns.F, culture );
            }
            else {
                var eraDate = new Date( value.getTime() ),
                    era = getEra( value, cal.eras );
                eraDate.setFullYear( getEraYear(value, cal, era) );
                ret = eraDate.toLocaleString();
            }
        }
        else {
            ret = value.toString();
        }
        return ret;
    }

    var eras = cal.eras,
        sortable = format === "
s";
    format = expandFormat( cal, format );

    // Start with an empty string
    ret = [];
    var hour,
        zeros = [ "
0", "00", "000" ],
        foundDay,
        checkedDay,
        dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g,
        quoteCount = 0,
        tokenRegExp = getTokenRegExp(),
        converted;

    function padZeros( num, c ) {
        var r, s = num + "";
        if ( c > 1 && s.length < c ) {
            r = ( zeros[c - 2] + s);
            return r.substr( r.length - c, c );
        }
        else {
            r = s;
        }
        return r;
    }

    function hasDay() {
        if ( foundDay || checkedDay ) {
            return foundDay;
        }
        foundDay = dayPartRegExp.test( format );
        checkedDay = true;
        return foundDay;
    }

    function getPart( date, part ) {
        if ( converted ) {
            return converted[ part ];
        }
        switch ( part ) {
            case 0: return date.getFullYear();
            case 1: return date.getMonth();
            case 2: return date.getDate();
        }
    }

    if ( !sortable && convert ) {
        converted = convert.fromGregorian( value );
    }

    for ( ; ; ) {
        // Save the current index
        var index = tokenRegExp.lastIndex,
            // Look for the next pattern
            ar = tokenRegExp.exec( format );

        // Append the text before the pattern (or the end of the string if not found)
        var preMatch = format.slice( index, ar ? ar.index : format.length );
        quoteCount += appendPreOrPostMatch( preMatch, ret );

        if ( !ar ) {
            break;
        }

        // do not replace any matches that occur inside a string literal.
        if ( quoteCount % 2 ) {
            ret.push( ar[0] );
            continue;
        }

        var current = ar[ 0 ],
            clength = current.length;

        switch ( current ) {
            case "
ddd":
                //Day of the week, as a three-letter abbreviation
            case "
dddd":
                // Day of the week, using the full name
                var names = ( clength === 3 ) ? cal.days.namesAbbr : cal.days.names;
                ret.push( names[value.getDay()] );
                break;
            case "
d":
                // Day of month, without leading zero for single-digit days
            case "
dd":
                // Day of month, with leading zero for single-digit days
                foundDay = true;
                ret.push(
                    padZeros( getPart(value, 2), clength )
                );
                break;
            case "
MMM":
                // Month, as a three-letter abbreviation
            case "
MMMM":
                // Month, using the full name
                var part = getPart( value, 1 );
                ret.push(
                    ( cal.monthsGenitive && hasDay() )
                    ?
                    cal.monthsGenitive[ clength === 3 ? "
namesAbbr" : "names" ][ part ]
                    :
                    cal.months[ clength === 3 ? "
namesAbbr" : "names" ][ part ]
                );
                break;
            case "
M":
                // Month, as digits, with no leading zero for single-digit months
            case "
MM":
                // Month, as digits, with leading zero for single-digit months
                ret.push(
                    padZeros( getPart(value, 1) + 1, clength )
                );
                break;
            case "
y":
                // Year, as two digits, but with no leading zero for years less than 10
            case "
yy":
                // Year, as two digits, with leading zero for years less than 10
            case "
yyyy":
                // Year represented by four full digits
                part = converted ? converted[ 0 ] : getEraYear( value, cal, getEra(value, eras), sortable );
                if ( clength < 4 ) {
                    part = part % 100;
                }
                ret.push(
                    padZeros( part, clength )
                );
                break;
            case "
h":
                // Hours with no leading zero for single-digit hours, using 12-hour clock
            case "
hh":
                // Hours with leading zero for single-digit hours, using 12-hour clock
                hour = value.getHours() % 12;
                if ( hour === 0 ) hour = 12;
                ret.push(
                    padZeros( hour, clength )
                );
                break;
            case "
H":
                // Hours with no leading zero for single-digit hours, using 24-hour clock
            case "
HH":
                // Hours with leading zero for single-digit hours, using 24-hour clock
                ret.push(
                    padZeros( value.getHours(), clength )
                );
                break;
            case "
m":
                // Minutes with no leading zero for single-digit minutes
            case "
mm":
                // Minutes with leading zero for single-digit minutes
                ret.push(
                    padZeros( value.getMinutes(), clength )
                );
                break;
            case "
s":
                // Seconds with no leading zero for single-digit seconds
            case "
ss":
                // Seconds with leading zero for single-digit seconds
                ret.push(
                    padZeros( value.getSeconds(), clength )
                );
                break;
            case "
t":
                // One character am/pm indicator ("
a" or "p")
            case "
tt":
                // Multicharacter am/pm indicator
                part = value.getHours() < 12 ? ( cal.AM ? cal.AM[0] : " " ) : ( cal.PM ? cal.PM[0] : " " );
                ret.push( clength === 1 ? part.charAt(0) : part );
                break;
            case "
f":
                // Deciseconds
            case "
ff":
                // Centiseconds
            case "
fff":
                // Milliseconds
                ret.push(
                    padZeros( value.getMilliseconds(), 3 ).substr( 0, clength )
                );
                break;
            case "
z":
                // Time zone offset, no leading zero
            case "
zz":
                // Time zone offset with leading zero
                hour = value.getTimezoneOffset() / 60;
                ret.push(
                    ( hour <= 0 ? "
+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), clength )
                );
                break;
            case "
zzz":
                // Time zone offset with leading zero
                hour = value.getTimezoneOffset() / 60;
                ret.push(
                    ( hour <= 0 ? "
+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), 2 )
                    // Hard coded "
:" separator, rather than using cal.TimeSeparator
                    // Repeated here for consistency, plus "
:" was already assumed in date parsing.
                    + "
:" + padZeros( Math.abs(value.getTimezoneOffset() % 60), 2 )
                );
                break;
            case "
g":
            case "
gg":
                if ( cal.eras ) {
                    ret.push(
                        cal.eras[ getEra(value, eras) ].name
                    );
                }
                break;
        case "
/":
            ret.push( cal["
/"] );
            break;
        default:
            throw "
Invalid date format pattern '" + current + "'.";
            break;
        }
    }
    return ret.join( "" );
};

// formatNumber
(function() {
    var expandNumber;

    expandNumber = function( number, precision, formatInfo ) {
        var groupSizes = formatInfo.groupSizes,
            curSize = groupSizes[ 0 ],
            curGroupIndex = 1,
            factor = Math.pow( 10, precision ),
            rounded = Math.round( number * factor ) / factor;

        if ( !isFinite(rounded) ) {
            rounded = number;
        }
        number = rounded;

        var numberString = number+"",
            right = "",
            split = numberString.split( /e/i ),
            exponent = split.length > 1 ? parseInt( split[1], 10 ) : 0;
        numberString = split[ 0 ];
        split = numberString.split( "
." );
        numberString = split[ 0 ];
        right = split.length > 1 ? split[ 1 ] : "";

        var l;
        if ( exponent > 0 ) {
            right = zeroPad( right, exponent, false );
            numberString += right.slice( 0, exponent );
            right = right.substr( exponent );
        }
        else if ( exponent < 0 ) {
            exponent = -exponent;
            numberString = zeroPad( numberString, exponent + 1 );
            right = numberString.slice( -exponent, numberString.length ) + right;
            numberString = numberString.slice( 0, -exponent );
        }

        if ( precision > 0 ) {
            right = formatInfo[ "
." ] +
                ( (right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision) );
        }
        else {
            right = "";
        }

        var stringIndex = numberString.length - 1,
            sep = formatInfo[ "
," ],
            ret = "";

        while ( stringIndex >= 0 ) {
            if ( curSize === 0 || curSize > stringIndex ) {
                return numberString.slice( 0, stringIndex + 1 ) + ( ret.length ? (sep + ret + right) : right );
            }
            ret = numberString.slice( stringIndex - curSize + 1, stringIndex + 1 ) + ( ret.length ? (sep + ret) : "" );

            stringIndex -= curSize;

            if ( curGroupIndex < groupSizes.length ) {
                curSize = groupSizes[ curGroupIndex ];
                curGroupIndex++;
            }
        }

        return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right;
    };

    formatNumber = function( value, format, culture ) {
        if ( !isFinite(value) ) {
            if ( value === Infinity ) {
                return culture.numberFormat.positiveInfinity;
            }
            if ( value === -Infinity ) {
                return culture.numberFormat.negativeInfinity;
            }
            return culture.numberFormat.NaN;
        }
        if ( !format || format === "
i" ) {
            return culture.name.length ? value.toLocaleString() : value.toString();
        }
        format = format || "
D";

        var nf = culture.numberFormat,
            number = Math.abs( value ),
            precision = -1,
            pattern;
        if ( format.length > 1 ) precision = parseInt( format.slice(1), 10 );

        var current = format.charAt( 0 ).toUpperCase(),
            formatInfo;

        switch ( current ) {
            case "
D":
                pattern = "
n";
                number = truncate( number );
                if ( precision !== -1 ) {
                    number = zeroPad( "" + number, precision, true );
                }
                if ( value < 0 ) number = "
-" + number;
                break;
            case "
N":
                formatInfo = nf;
                // fall through
            case "
C":
                formatInfo = formatInfo || nf.currency;
                // fall through
            case "
P":
                formatInfo = formatInfo || nf.percent;
                pattern = value < 0 ? formatInfo.pattern[ 0 ] : ( formatInfo.pattern[1] || "
n" );
                if ( precision === -1 ) precision = formatInfo.decimals;
                number = expandNumber( number * (current === "
P" ? 100 : 1), precision, formatInfo );
                break;
            default:
                throw "
Bad number format specifier" + current;
        }

        var patternParts = /n|$|-|%/g,
            ret = "";
        for ( ; ; ) {
            var index = patternParts.lastIndex,
                ar = patternParts.exec( pattern );

            ret += pattern.slice( index, ar ? ar.index : pattern.length );

            if ( !ar ) {
                break;
            }

            switch ( ar[0] ) {
                case "
n":
                    ret += number;
                    break;
                case "
$":
                    ret += nf.currency.symbol;
                    break;
                case "
-":
                    // don't make 0 negative
                    if ( /[1-9]/.test(number) ) {
                        ret += nf[ "
-" ];
                    }
                    break;
                case "
%":
                    ret += nf.percent.symbol;
                    break;
            }
        }

        return ret;
    };

}());

getTokenRegExp = function() {
    // regular expression for matching date and time tokens in format strings.
    return //|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g;
};

getEra = function( date, eras ) {
    if ( !eras ) return 0;
    var start, ticks = date.getTime();
    for ( var i = 0, l = eras.length; i < l; i++ ) {
        start = eras[ i ].start;
        if ( start === null || ticks >= start ) {
            return i;
        }
    }
    return 0;
};

getEraYear = function( date, cal, era, sortable ) {
    var year = date.getFullYear();
    if ( !sortable && cal.eras ) {
        // convert normal gregorian year to era-shifted gregorian
        // year by subtracting the era offset
        year -= cal.eras[ era ].offset;
    }
    return year;
};

// parseExact
(function() {
    var expandYear,
        getDayIndex,
        getMonthIndex,
        getParseRegExp,
        outOfRange,
        toUpper,
        toUpperArray;

    expandYear = function( cal, year ) {
        // expands 2-digit year into 4 digits.
        var now = new Date(),
            era = getEra( now );
        if ( year < 100 ) {
            var twoDigitYearMax = cal.twoDigitYearMax;
            twoDigitYearMax = typeof twoDigitYearMax === "
string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
            var curr = getEraYear( now, cal, era );
            year += curr - ( curr % 100 );
            if ( year > twoDigitYearMax ) {
                year -= 100;
            }
        }
        return year;
    };

    getDayIndex = function    ( cal, value, abbr ) {
        var ret,
            days = cal.days,
            upperDays = cal._upperDays;
        if ( !upperDays ) {
            cal._upperDays = upperDays = [
                toUpperArray( days.names ),
                toUpperArray( days.namesAbbr ),
                toUpperArray( days.namesShort )
            ];
        }
        value = toUpper( value );
        if ( abbr ) {
            ret = arrayIndexOf( upperDays[1], value );
            if ( ret === -1 ) {
                ret = arrayIndexOf( upperDays[2], value );
            }
        }
        else {
            ret = arrayIndexOf( upperDays[0], value );
        }
        return ret;
    };

    getMonthIndex = function( cal, value, abbr ) {
        var months = cal.months,
            monthsGen = cal.monthsGenitive || cal.months,
            upperMonths = cal._upperMonths,
            upperMonthsGen = cal._upperMonthsGen;
        if ( !upperMonths ) {
            cal._upperMonths = upperMonths = [
                toUpperArray( months.names ),
                toUpperArray( months.namesAbbr )
            ];
            cal._upperMonthsGen = upperMonthsGen = [
                toUpperArray( monthsGen.names ),
                toUpperArray( monthsGen.namesAbbr )
            ];
        }
        value = toUpper( value );
        var i = arrayIndexOf( abbr ? upperMonths[1] : upperMonths[0], value );
        if ( i < 0 ) {
            i = arrayIndexOf( abbr ? upperMonthsGen[1] : upperMonthsGen[0], value );
        }
        return i;
    };

    getParseRegExp = function( cal, format ) {
        // converts a format string into a regular expression with groups that
        // can be used to extract date fields from a date string.
        // check for a cached parse regex.
        var re = cal._parseRegExp;
        if ( !re ) {
            cal._parseRegExp = re = {};
        }
        else {
            var reFormat = re[ format ];
            if ( reFormat ) {
                return reFormat;
            }
        }

        // expand single digit formats, then escape regular expression characters.
        var expFormat = expandFormat( cal, format ).replace( /([^$.*+?|[](){}])/g, "
\\$1" ),
            regexp = [ "
^" ],
            groups = [],
            index = 0,
            quoteCount = 0,
            tokenRegExp = getTokenRegExp(),
            match;

        // iterate through each date token found.
        while ( (match = tokenRegExp.exec(expFormat)) !== null ) {
            var preMatch = expFormat.slice( index, match.index );
            index = tokenRegExp.lastIndex;

            // don't replace any matches that occur inside a string literal.
            quoteCount += appendPreOrPostMatch( preMatch, regexp );
            if ( quoteCount % 2 ) {
                regexp.push( match[0] );
                continue;
            }

            // add a regex group for the token.
            var m = match[ 0 ],
                len = m.length,
                add;
            switch ( m ) {
                case "
dddd": case "ddd":
                case "
MMMM": case "MMM":
                case "
gg": case "g":
                    add = "
(\D+)";
                    break;
                case "
tt": case "t":
                    add = "
(\D*)";
                    break;
                case "
yyyy":
                case "
fff":
                case "
ff":
                case "
f":
                    add = "
(\d{" + len + "})";
                    break;
                case "
dd": case "d":
                case "
MM": case "M":
                case "
yy": case "y":
                case "
HH": case "H":
                case "
hh": case "h":
                case "
mm": case "m":
                case "
ss": case "s":
                    add = "
(\d\d?)";
                    break;
                case "
zzz":
                    add = "
([+-]?\d\d?:\d{2})";
                    break;
                case "
zz": case "z":
                    add = "
([+-]?\d\d?)";
                    break;
                case "
/":
                    add = "
(\" + cal[ "/" ] + ")";
                    break;
                default:
                    throw "
Invalid date format pattern '" + m + "'.";
                    break;
            }
            if ( add ) {
                regexp.push( add );
            }
            groups.push( match[0] );
        }
        appendPreOrPostMatch( expFormat.slice(index), regexp );
        regexp.push( "
$" );

        // allow whitespace to differ when matching formats.
        var regexpStr = regexp.join( "" ).replace( /s+/g, "
\s+" ),
            parseRegExp = { "
regExp": regexpStr, "groups": groups };

        // cache the regex for this format.
        return re[ format ] = parseRegExp;
    };

    outOfRange = function( value, low, high ) {
        return value < low || value > high;
    };

    toUpper = function( value ) {
        // "
he-IL" has non-breaking space in weekday names.
        return value.split( "
u00A0" ).join( " " ).toUpperCase();
    };

    toUpperArray = function( arr ) {
        var results = [];
        for ( var i = 0, l = arr.length; i < l; i++ ) {
            results[ i ] = toUpper( arr[i] );
        }
        return results;
    };

    parseExact = function( value, format, culture ) {
        // try to parse the date string by matching against the format string
        // while using the specified culture for date field names.
        value = trim( value );
        var cal = culture.calendar,
            // convert date formats into regular expressions with groupings.
            // use the regexp to determine the input format and extract the date fields.
            parseInfo = getParseRegExp( cal, format ),
            match = new RegExp( parseInfo.regExp ).exec( value );
        if ( match === null ) {
            return null;
        }
        // found a date format that matches the input.
        var groups = parseInfo.groups,
            era = null, year = null, month = null, date = null, weekDay = null,
            hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null,
            pmHour = false;
        // iterate the format groups to extract and set the date fields.
        for ( var j = 0, jl = groups.length; j < jl; j++ ) {
            var matchGroup = match[ j + 1 ];
            if ( matchGroup ) {
                var current = groups[ j ],
                    clength = current.length,
                    matchInt = parseInt( matchGroup, 10 );
                switch ( current ) {
                    case "
dd": case "d":
                        // Day of month.
                        date = matchInt;
                        // check that date is generally in valid range, also checking overflow below.
                        if ( outOfRange(date, 1, 31) ) return null;
                        break;
                    case "
MMM": case "MMMM":
                        month = getMonthIndex( cal, matchGroup, clength === 3 );
                        if ( outOfRange(month, 0, 11) ) return null;
                        break;
                    case "
M": case "MM":
                        // Month.
                        month = matchInt - 1;
                        if ( outOfRange(month, 0, 11) ) return null;
                        break;
                    case "
y": case "yy":
                    case "
yyyy":
                        year = clength < 4 ? expandYear( cal, matchInt ) : matchInt;
                        if ( outOfRange(year, 0, 9999) ) return null;
                        break;
                    case "
h": case "hh":
                        // Hours (12-hour clock).
                        hour = matchInt;
                        if ( hour === 12 ) hour = 0;
                        if ( outOfRange(hour, 0, 11) ) return null;
                        break;
                    case "
H": case "HH":
                        // Hours (24-hour clock).
                        hour = matchInt;
                        if ( outOfRange(hour, 0, 23) ) return null;
                        break;
                    case "
m": case "mm":
                        // Minutes.
                        min = matchInt;
                        if ( outOfRange(min, 0, 59) ) return null;
                        break;
                    case "
s": case "ss":
                        // Seconds.
                        sec = matchInt;
                        if ( outOfRange(sec, 0, 59) ) return null;
                        break;
                    case "
tt": case "t":
                        // AM/PM designator.
                        // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of
                        // the AM tokens. If not, fail the parse for this format.
                        pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] );
                        if (
                            !pmHour && (
                                !cal.AM || ( matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2] )
                            )
                        ) return null;
                        break;
                    case "
f":
                        // Deciseconds.
                    case "
ff":
                        // Centiseconds.
                    case "
fff":
                        // Milliseconds.
                        msec = matchInt * Math.pow( 10, 3 - clength );
                        if ( outOfRange(msec, 0, 999) ) return null;
                        break;
                    case "
ddd":
                        // Day of week.
                    case "
dddd":
                        // Day of week.
                        weekDay = getDayIndex( cal, matchGroup, clength === 3 );
                        if ( outOfRange(weekDay, 0, 6) ) return null;
                        break;
                    case "
zzz":
                        // Time zone offset in +/- hours:min.
                        var offsets = matchGroup.split( /:/ );
                        if ( offsets.length !== 2 ) return null;
                        hourOffset = parseInt( offsets[0], 10 );
                        if ( outOfRange(hourOffset, -12, 13) ) return null;
                        var minOffset = parseInt( offsets[1], 10 );
                        if ( outOfRange(minOffset, 0, 59) ) return null;
                        tzMinOffset = ( hourOffset * 60 ) + ( startsWith(matchGroup, "
-") ? -minOffset : minOffset );
                        break;
                    case "
z": case "zz":
                        // Time zone offset in +/- hours.
                        hourOffset = matchInt;
                        if ( outOfRange(hourOffset, -12, 13) ) return null;
                        tzMinOffset = hourOffset * 60;
                        break;
                    case "
g": case "gg":
                        var eraName = matchGroup;
                        if ( !eraName || !cal.eras ) return null;
                        eraName = trim( eraName.toLowerCase() );
                        for ( var i = 0, l = cal.eras.length; i < l; i++ ) {
                            if ( eraName === cal.eras[i].name.toLowerCase() ) {
                                era = i;
                                break;
                            }
                        }
                        // could not find an era with that name
                        if ( era === null ) return null;
                        break;
                }
            }
        }
        var result = new Date(), defaultYear, convert = cal.convert;
        defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear();
        if ( year === null ) {
            year = defaultYear;
        }
        else if ( cal.eras ) {
            // year must be shifted to normal gregorian year
            // but not if year was not specified, its already normal gregorian
            // per the main if clause above.
            year += cal.eras[( era || 0 )].offset;
        }
        // set default day and month to 1 and January, so if unspecified, these are the defaults
        // instead of the current day/month.
        if ( month === null ) {
            month = 0;
        }
        if ( date === null ) {
            date = 1;
        }
        // now have year, month, and date, but in the culture's calendar.
        // convert to gregorian if necessary
        if ( convert ) {
            result = convert.toGregorian( year, month, date );
            // conversion failed, must be an invalid match
            if ( result === null ) return null;
        }
        else {
            // have to set year, month and date together to avoid overflow based on current date.
            result.setFullYear( year, month, date );
            // check to see if date overflowed for specified month (only checked 1-31 above).
            if ( result.getDate() !== date ) return null;
            // invalid day of week.
            if ( weekDay !== null && result.getDay() !== weekDay ) {
                return null;
            }
        }
        // if pm designator token was found make sure the hours fit the 24-hour clock.
        if ( pmHour && hour < 12 ) {
            hour += 12;
        }
        result.setHours( hour, min, sec, msec );
        if ( tzMinOffset !== null ) {
            // adjust timezone to utc before applying local offset.
            var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() );
            // Safari limits hours and minutes to the range of -127 to 127.     We need to use setHours
            // to ensure both these fields will not exceed this range.    adjustedMin will range
            // somewhere between -1440 and 1500, so we only need to split this into hours.
            result.setHours( result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60 );
        }
        return result;
    };
}());

parseNegativePattern = function( value, nf, negativePattern ) {
    var neg = nf[ "
-" ],
        pos = nf[ "
+" ],
        ret;
    switch ( negativePattern ) {
        case "
-":
            neg = " " + neg;
            pos = " " + pos;
            // fall through
        case "
n-":
            if ( endsWith(value, neg) ) {
                ret = [ "
-", value.substr(0, value.length - neg.length) ];
            }
            else if ( endsWith(value, pos) ) {
                ret = [ "
+", value.substr(0, value.length - pos.length) ];
            }
            break;
        case "
n":
            neg += " ";
            pos += " ";
            // fall through
        case "
-n":
            if ( startsWith(value, neg) ) {
                ret = [ "
-", value.substr(neg.length) ];
            }
            else if ( startsWith(value, pos) ) {
                ret = [ "
+", value.substr(pos.length) ];
            }
            break;
        case "
(n)":
            if ( startsWith(value, "
(") && endsWith(value, ")") ) {
                ret = [ "
-", value.substr(1, value.length - 2) ];
            }
            break;
    }
    return ret || [ "", value ];
};

//
// public instance functions
//

Globalize.prototype.findClosestCulture = function( cultureSelector ) {
    return Globalize.findClosestCulture.call( this, cultureSelector );
};

Globalize.prototype.format = function( value, format, cultureSelector ) {
    return Globalize.format.call( this, value, format, cultureSelector );
};

Globalize.prototype.localize = function( key, cultureSelector ) {
    return Globalize.localize.call( this, key, cultureSelector );
};

Globalize.prototype.parseInt = function( value, radix, cultureSelector ) {
    return Globalize.parseInt.call( this, value, radix, cultureSelector );
};

Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) {
    return Globalize.parseFloat.call( this, value, radix, cultureSelector );
};

Globalize.prototype.culture = function( cultureSelector ) {
    return Globalize.culture.call( this, cultureSelector );
};

//
// public singleton functions
//

Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) {

    var base = {},
        isNew = false;

    if ( typeof cultureName !== "
string" ) {
        // cultureName argument is optional string. If not specified, assume info is first
        // and only argument. Specified info deep-extends current culture.
        info = cultureName;
        cultureName = this.culture().name;
        base = this.cultures[ cultureName ];
    } else if ( typeof baseCultureName !== "
string" ) {
        // baseCultureName argument is optional string. If not specified, assume info is second
        // argument. Specified info deep-extends specified culture.
        // If specified culture does not exist, create by deep-extending default
        info = baseCultureName;
        isNew = ( this.cultures[ cultureName ] == null );
        base = this.cultures[ cultureName ] || this.cultures[ "
default" ];
    } else {
        // cultureName and baseCultureName specified. Assume a new culture is being created
        // by deep-extending an specified base culture
        isNew = true;
        base = this.cultures[ baseCultureName ];
    }

    this.cultures[ cultureName ] = extend(true, {},
        base,
        info
    );
    // Make the standard calendar the current culture if it's a new culture
    if ( isNew ) {
        this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard;
    }
};

Globalize.findClosestCulture = function( name ) {
    var match;
    if ( !name ) {
        return this.cultures[ this.cultureSelector ] || this.cultures[ "
default" ];
    }
    if ( typeof name === "
string" ) {
        name = name.split( "
," );
    }
    if ( isArray(name) ) {
        var lang,
            cultures = this.cultures,
            list = name,
            i, l = list.length,
            prioritized = [];
        for ( i = 0; i < l; i++ ) {
            name = trim( list[i] );
            var pri, parts = name.split( "
;" );
            lang = trim( parts[0] );
            if ( parts.length === 1 ) {
                pri = 1;
            }
            else {
                name = trim( parts[1] );
                if ( name.indexOf("
q=") === 0 ) {
                    name = name.substr( 2 );
                    pri = parseFloat( name );
                    pri = isNaN( pri ) ? 0 : pri;
                }
                else {
                    pri = 1;
                }
            }
            prioritized.push({ lang: lang, pri: pri });
        }
        prioritized.sort(function( a, b ) {
            return a.pri < b.pri ? 1 : -1;
        });

        // exact match
        for ( i = 0; i < l; i++ ) {
            lang = prioritized[ i ].lang;
            match = cultures[ lang ];
            if ( match ) {
                return match;
            }
        }

        // neutral language match
        for ( i = 0; i < l; i++ ) {
            lang = prioritized[ i ].lang;
            do {
                var index = lang.lastIndexOf( "
-" );
                if ( index === -1 ) {
                    break;
                }
                // strip off the last part. e.g. en-US => en
                lang = lang.substr( 0, index );
                match = cultures[ lang ];
                if ( match ) {
                    return match;
                }
            }
            while ( 1 );
        }

        // last resort: match first culture using that language
        for ( i = 0; i < l; i++ ) {
            lang = prioritized[ i ].lang;
            for ( var cultureKey in cultures ) {
                var culture = cultures[ cultureKey ];
                if ( culture.language == lang ) {
                    return culture;
                }
            }
        }
    }
    else if ( typeof name === "
object" ) {
        return name;
    }
    return match || null;
};

Globalize.format = function( value, format, cultureSelector ) {
    culture = this.findClosestCulture( cultureSelector );
    if ( value instanceof Date ) {
        value = formatDate( value, format, culture );
    }
    else if ( typeof value === "
number" ) {
        value = formatNumber( value, format, culture );
    }
    return value;
};

Globalize.localize = function( key, cultureSelector ) {
    return this.findClosestCulture( cultureSelector ).messages[ key ] ||
        this.cultures[ "
default" ].messages[ key ];
};

Globalize.parseDate = function( value, formats, culture ) {
    culture = this.findClosestCulture( culture );

    var date, prop, patterns;
    if ( formats ) {
        if ( typeof formats === "
string" ) {
            formats = [ formats ];
        }
        if ( formats.length ) {
            for ( var i = 0, l = formats.length; i < l; i++ ) {
                var format = formats[ i ];
                if ( format ) {
                    date = parseExact( value, format, culture );
                    if ( date ) {
                        break;
                    }
                }
            }
        }
    } else {
        patterns = culture.calendar.patterns;
        for ( prop in patterns ) {
            date = parseExact( value, patterns[prop], culture );
            if ( date ) {
                break;
            }
        }
    }

    return date || null;
};

Globalize.parseInt = function( value, radix, cultureSelector ) {
    return truncate( Globalize.parseFloat(value, radix, cultureSelector) );
};

Globalize.parseFloat = function( value, radix, cultureSelector ) {
    // radix argument is optional
    if ( typeof radix !== "
number" ) {
        cultureSelector = radix;
        radix = 10;
    }

    var culture = this.findClosestCulture( cultureSelector );
    var ret = NaN,
        nf = culture.numberFormat;

    if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) {
        // remove currency symbol
        value = value.replace( culture.numberFormat.currency.symbol, "" );
        // replace decimal seperator
        value = value.replace( culture.numberFormat.currency["
."], culture.numberFormat["."] );
    }

    // trim leading and trailing whitespace
    value = trim( value );

    // allow infinity or hexidecimal
    if ( regexInfinity.test(value) ) {
        ret = parseFloat( value );
    }
    else if ( !radix && regexHex.test(value) ) {
        ret = parseInt( value, 16 );
    }
    else {

        // determine sign and number
        var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
            sign = signInfo[ 0 ],
            num = signInfo[ 1 ];

        // #44 - try parsing as "
(n)"
        if ( sign === "" && nf.pattern[0] !== "
(n)" ) {
            signInfo = parseNegativePattern( value, nf, "
(n)" );
            sign = signInfo[ 0 ];
            num = signInfo[ 1 ];
        }

        // try parsing as "
-n"
        if ( sign === "" && nf.pattern[0] !== "
-n" ) {
            signInfo = parseNegativePattern( value, nf, "
-n" );
            sign = signInfo[ 0 ];
            num = signInfo[ 1 ];
        }

        sign = sign || "
+";

        // determine exponent and number
        var exponent,
            intAndFraction,
            exponentPos = num.indexOf( "
e" );
        if ( exponentPos < 0 ) exponentPos = num.indexOf( "
E" );
        if ( exponentPos < 0 ) {
            intAndFraction = num;
            exponent = null;
        }
        else {
            intAndFraction = num.substr( 0, exponentPos );
            exponent = num.substr( exponentPos + 1 );
        }
        // determine decimal position
        var integer,
            fraction,
            decSep = nf[ "
." ],
            decimalPos = intAndFraction.indexOf( decSep );
        if ( decimalPos < 0 ) {
            integer = intAndFraction;
            fraction = null;
        }
        else {
            integer = intAndFraction.substr( 0, decimalPos );
            fraction = intAndFraction.substr( decimalPos + decSep.length );
        }
        // handle groups (e.g. 1,000,000)
        var groupSep = nf[ "
," ];
        integer = integer.split( groupSep ).join( "" );
        var altGroupSep = groupSep.replace( /u00A0/g, " " );
        if ( groupSep !== altGroupSep ) {
            integer = integer.split( altGroupSep ).join( "" );
        }
        // build a natively parsable number string
        var p = sign + integer;
        if ( fraction !== null ) {
            p += "
." + fraction;
        }
        if ( exponent !== null ) {
            // exponent itself may have a number patternd
            var expSignInfo = parseNegativePattern( exponent, nf, "
-n" );
            p += "
e" + ( expSignInfo[0] || "+" ) + expSignInfo[ 1 ];
        }
        if ( regexParseFloat.test(p) ) {
            ret = parseFloat( p );
        }
    }
    return ret;
};

Globalize.culture = function( cultureSelector ) {
    // setter
    if ( typeof cultureSelector !== "
undefined" ) {
        this.cultureSelector = cultureSelector;
    }
    // getter
    return this.findClosestCulture( cultureSelector ) || this.culture[ "
default" ];
};

}( this ));
?>
Онлайн: 2
Реклама