﻿var JavaScript = {};

/// <summary>The exception that is thrown when a null reference is passed to a method that does not accept it as a valid argument.</summary>
JavaScript.ArgumentNullException = ArgumentNullException = function(object) {
    base = new Error(object);
    return base;
};

/// <summary>The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method.</summary>
JavaScript.ArgumentOutOfRangeException = ArgumentOutOfRangeException = function(object) {
    base = new Error(object);
    return base;
};

JavaScript.Convert = Convert = {};

JavaScript.Convert.FromBase64String = function(value) {
    var output = "", key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
        char1, char2, char3, encr1, encr2, encr3, encr4, i = 0;

    value = value.replace(/[^A-z0-9\+\/\=]/g, "");

    while (i < value.length) {
        encr1 = key.indexOf(value.charAt(i++));
        encr2 = key.indexOf(value.charAt(i++));
        encr3 = key.indexOf(value.charAt(i++));
        encr4 = key.indexOf(value.charAt(i++));

        char1 = (encr1 << 2) | (encr2 >> 4);
        char2 = ((encr2 & 15) << 4) | (encr3 >> 2);
        char3 = ((encr3 & 3) << 6) | encr4;

        output = output + String.fromCharCode(char1);

        if (encr3 != 64) output = output + String.fromCharCode(char2);
        if (encr4 != 64) output = output + String.fromCharCode(char3);
    };

    return JavaScript.Text.UTF8Encoding.Decode(output);
};

JavaScript.Convert.ToBase64String = function(value) {
    var output = "", key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
        chra1, chra2, char3, encr1, encr2, encr3, encr4, i = 0;

    value = System.Text.UTF8Encoding.Encode(value);

    while (i < value.length) {
        char1 = value.charCodeAt(i++);
        char2 = value.charCodeAt(i++);
        char3 = value.charCodeAt(i++);

        enc1 = char1 >> 2;
        enc2 = ((char1 & 3) << 4) | (char2 >> 4);
        enc3 = ((char2 & 15) << 2) | (char3 >> 6);
        enc4 = char3 & 63;

        if (isNaN(char2)) {
            encr3 = encr4 = 64;
        } else if (isNaN(char3)) {
            encr4 = 64;
        }

        output = output + key.charAt(encr1) + key.charAt(encr2) + key.charAt(encr3) + key.charAt(encr4);
    };

    return base64value;
};

/// <summary>Specifies the day of the week.</summary>
JavaScript.DayOfWeek = DayOfWeek = {
    Sunday: 0, '0': 'Sunday',
    Monday: 1, '1': 'Monday',
    Tuesday: 2, '2': 'Tuesday',
    Wednesday: 3, '3': 'Wednesday',
    Thursday: 4, '4': 'Thursday',
    Friday: 5, '5': 'Friday',
    Saturday: 6, '6': 'Saturday'
};

/// <summary>Initializes a new instance of the DateTime structure to the specified year, month, day, hour, minute, second, and millisecond.</summary>
/// <param name="year">The year (1 through 9999).</param>
/// <param name="month">The month (1 through 12).</param>
/// <param name="day">The day (1 through the number of days in month).</param>
/// <param name="hour">The hours (0 through 23).</param>
/// <param name="minute">The minutes (0 through 59).</param>
/// <param name="second">The seconds (0 through 59).</param>
/// <param name="millisecond">The milliseconds (0 through 999).</param>
/// <exceptions cref-"JavaScript.ArgumentOutOfRangeException">
///   year is less than 1 or greater than 9999. -or- month is less than 1 or greater than 12.-or- day is less than 1 or greater than the number of days in month. -or- hour is less
///   than 0 or greater than 23.-or- minute is less than 0 or greater than 59.-or- second is less than 0 or greater than 59.-or- millisecond is less than 0 or greater than 999.
/// <exeptions>
JavaScript.DateTime = DateTime = function(year, month, day, hour, minute, second, millisecond) {
    if (year < 1 || year > 0x270f) throw new JavaScript.ArgumentOutOfRangeException("year");
    if (month < 1 || month > 12) throw new JavaScript.ArgumentOutOfRangeException("month");
    if (day < 1 || day > JavaScript.DateTime.DaysInMonth(year, month)) throw new JavaScript.ArgumentOutOfRangeException("day");
    if (hour < 0 || hour > 23) throw new JavaScript.ArgumentOutOfRangeException("hour");
    if (minute < 0 || minute > 59) throw new JavaScript.ArgumentOutOfRangeException("minute");
    if (second < 0 || second > 59) throw new JavaScript.ArgumentOutOfRangeException("second");
    if (millisecond < 0 || millisecond > 999) throw new JavaScript.ArgumentOutOfRangeException("millisecond");

    var self = this, base = new Date(year, month - 1, day, hour || 0, minute || 0, second | 0, millisecond || 0);
    this.Day = base.getDate();
    this.DayOfWeek = base.getDay();
    this.DayOfYear = Math.ceil((base - new Date(base.getFullYear(), 0, 1)) / 86400000);
    this.Hour = base.getHours();
    this.Millisecond = base.getMilliseconds();
    this.Minute = base.getMinutes();
    this.Month = base.getMonth() + 1;
    this.Second = base.getSeconds();
    this.TimeOfDay = base.getTime();
    this.TimeZoneOffset = base.getTimezoneOffset();
    this.UTCDay = base.getUTCDate();
    this.UTCDayOfWeek = base.getUTCDay();
    this.UTCHour = base.getUTCHours();
    this.UTCMillisecond = base.getUTCMilliseconds();
    this.UTCMinute = base.getUTCMinutes();
    this.UTCMonth = base.getUTCMonth();
    this.UTCSecond = base.getUTCSeconds();
    this.UTCYear = base.getUTCFullYear();
    this.Year = base.getFullYear();

    function FromJavaScriptDate(value) {
        return new DateTime(value.getFullYear(), value.getMonth() + 1, value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), value.getMilliseconds());
    }

    /// <summary>Converts the value of this instance to its equivalent long date string representation.</summary>
    /// <returns>
    ///   A string containing the name of the day of the week, the name of the month, the numeric day of the month, and the year equivalent to the date value of this instance.
    /// </returns>
    this.ToLongDateString = function() {
        return self.ToString('D');
    }

    /// <summary>Converts the value of this instance to its equivalent long time string representation.</summary>
    /// <returns>
    ///   A string containing the name of the day of the week, the name of the month, the numeric day of the hours, minutes, and seconds equivalent to the time value of this instance.
    /// </returns>
    this.ToLongTimeString = function() {
        return self.ToString('T');
    }

    /// <summary>Converts the value of this instance to its equivalent short date string representation.</summary>
    /// <returns>
    ///   A string containing the numeric month, the numeric day of the month, and the year equivalent to the date value of this instance.
    /// </returns>
    this.ToShortDateString = function() {
        return self.ToString('d');
    }

    /// <summary>Converts the value of this instance to its equivalent short time string representation.</summary>
    /// <returns>
    ///   A string containing the name of the day of the week, the name of the month, the numeric day of the hours, minutes, and seconds equivalent to the time value of this instance.
    /// </returns>
    this.ToShortTimeString = function() {
        return self.ToString('t');
    }

    /// <summary>Converts the value of this instance to its equivalent string representation using the specified format.</summary>
    /// <param name="format">A format string.</param>
    /// <returns>A string representation of value of this instance as specified by format.</returns>
    /// <exceptions cref="JavaScript.FormatException">
    ///   The length of format is 1, and it is not one of the format specifier characters defined for DateTimeFormatInfo. -or- format does not contain a valid custom format pattern.
    /// </exceptions>
    this.ToString = function(format) {
        switch (format || JavaScript.DateTimeFormats.GeneralDateLongTime) {
            case JavaScript.DateTimeFormats.ShortDate: // 'd'
                return String.Format(JavaScript.DateTimeFormats[format], this.Month, this.Day, String.PadLeft(this.Year.toString(), 4, '0'));
                break;
            case JavaScript.DateTimeFormats.LongDate: // 'D'
                return String.Format(JavaScript.DateTimeFormats[format], JavaScript.DayOfWeek[this.DayOfWeek], JavaScript.MonthOfYear[this.Month], String.PadLeft(this.Day.toString(), 2, '0'), String.PadLeft(this.Year.toString(), 4, '0'));
                break;
            case JavaScript.DateTimeFormats.ShortTime: // 't'
                return String.Format(JavaScript.DateTimeFormats[format], (this.Hour % 12 == 0 ? 12 : this.Hour % 12), String.PadLeft(this.Minute.toString(), 2, '0'), (this.Hour < 12) ? 'AM' : 'PM');
                break;
            case JavaScript.DateTimeFormats.LongTime: // 'T'
                return String.Format(JavaScript.DateTimeFormats[format], (this.Hour % 12 == 0 ? 12 : this.Hour % 12), String.PadLeft(this.Minute.toString(), 2, '0'), String.PadLeft(this.Second.toString(), 2, '0'), (this.Hour < 12) ? 'AM' : 'PM');
                break;
            case JavaScript.DateTimeFormats.FullDateShortTime: // 'f'
                return String.Format(JavaScript.DateTimeFormats[format], JavaScript.DayOfWeek[this.DayOfWeek], JavaScript.MonthOfYear[this.Month], String.PadLeft(this.Day.toString(), 2, '0'), String.PadLeft(this.Year.toString(), 4, '0'), (this.Hour % 12 == 0 ? 12 : this.Hour % 12), String.PadLeft(this.Minute.toString(), 2, '0'), (this.Hour < 12) ? 'AM' : 'PM');
                break;
            case JavaScript.DateTimeFormats.FullDateLongTime: // 'F'
                return String.Format(JavaScript.DateTimeFormats[format], JavaScript.DayOfWeek[this.DayOfWeek], JavaScript.MonthOfYear[this.Month], String.PadLeft(this.Day.toString(), 2, '0'), String.PadLeft(this.Year.toString(), 4, '0'), (this.Hour % 12 == 0 ? 12 : this.Hour % 12), String.PadLeft(this.Minute.toString(), 2, '0'), String.PadLeft(this.Second.toString(), 2, '0'), (this.Hour < 12) ? 'AM' : 'PM');
                break;
            case JavaScript.DateTimeFormats.GeneralDateShortTime: // 'g'
                return String.Format(JavaScript.DateTimeFormats[format], this.Month, this.Day, String.PadLeft(this.Year.toString(), 4, '0'), (this.Hour % 12 == 0 ? 12 : this.Hour % 12), String.PadLeft(this.Minute.toString(), 2, '0'), (this.Hour < 12) ? 'AM' : 'PM');
                break;
            case JavaScript.DateTimeFormats.GeneralDateLongTime: // 'G'
                return String.Format(JavaScript.DateTimeFormats[format], this.Month, this.Day, String.PadLeft(this.Year.toString(), 4, '0'), (this.Hour % 12 == 0 ? 12 : this.Hour % 12), String.PadLeft(this.Minute.toString(), 2, '0'), String.PadLeft(this.Second.toString(), 2, '0'), (this.Hour < 12) ? 'AM' : 'PM');
                break;
            case JavaScript.DateTimeFormats.Month: // 'M'
                return String.Format(JavaScript.DateTimeFormats[format], JavaScript.MonthOfYear[this.Month], String.PadLeft(this.Day.toString(), 2, '0'));
                break;
            case JavaScript.DateTimeFormats.RFC1123: // 'RFC1123'
                return base.toUTCString();
                break;
            case JavaScript.DateTimeFormats.Sortable: // 's'
                return String.Format(JavaScript.DateTimeFormats[format], String.PadLeft(this.Year.toString(), 4, '0'), String.PadLeft(this.Month.toString(), 2, '0'), String.PadLeft(this.Day.toString(), 2, '0'), String.PadLeft(this.Hour.toString(), 2, '0'), String.PadLeft(this.Minute.toString(), 2, '0'), String.PadLeft(this.Second.toString(), 2, '0'));
                break;
            case JavaScript.DateTimeFormats.UniversalSortableInvariant: // 'u'
                return String.Format(JavaScript.DateTimeFormats[format], this.UTCYear, String.PadLeft(this.UTCMonth.toString(), 2, '0'), String.PadLeft(this.UTCDay.toString(), 2, '0'), String.PadLeft(this.UTCHour.toString(), 2, '0'), String.PadLeft(this.UTCMinute.toString(), 2, '0'), String.PadLeft(this.UTCSecond.toString(), 2, '0'));
                break;
            case JavaScript.DateTimeFormats.UniversalSortable: // 'U'
                // TODO: Universal sortable: Monday, April 17, 2006 9:22:48 PM 
                break;
            case JavaScript.DateTimeFormats.Year: // 'Y'
                return String.Format(JavaScript.DateTimeFormats[format], JavaScript.MonthOfYear[this.Month], String.PadLeft(this.Year.toString(), 4, '0'));
                break;
            default:
                if (!String.IsNullOrEmpty(format)) throw new FormatException("format");
                return this.ToString(JavaScript.DateTimeFormats.GeneralDateLongTime);
                break;
        };
    };
};

/// <summary>Returns the number of days in the specified month and year.</summary>
/// <param name="year">A 4-digit year.</param>
/// <param name="month">A number ranging from 1 to 12</param>
/// <returns>
///   The number of days in month for the specified year.For example, if month equals 2 for February, the return value is 28 or 29 depending upon whether year is a leap year.
/// </returns>
/// <exceptions cref="JavaScript.ArgumentOutOfRangeException">month is less than 1 or greater than 12. -or- year is less than 1 or greater than 9999.</exceptions>
JavaScript.DateTime.DaysInMonth = function(year, month) {
    if (year < 1 || year > 0x270f) throw new JavaScript.ArgumentOutOfRangeException("year");
    if (month < 1 || month > 12) throw new JavaScript.ArgumentOutOfRangeException("month");
    return 32 - new Date(year, month - 1, 32).getDate();
};

/// <summary>Returns an indication whether the specified year is a leap year.</summary>
/// <param name="year">A 4-digit year.</param>
/// <returns>true if year is a leap year; otherwise, false.</returns>
/// <exceptions cref="JavaScript.ArgumentOutOfRangeException">year is less than 1 or greater than 9999.</exceptions>
JavaScript.DateTime.IsLeapYear = function(year) {
    if (year < 1 || year > 0x270f) throw new JavaScript.ArgumentOutOfRangeException("year");
    return ((year % 4) != 0 ? false : (year % 100) == 0 ? (year % 400) == 0 : true);
};

/// <summary>Represents the largest possible value of DateTime. This field is read-only.</summary>
JavaScript.DateTime.MaxValue = new JavaScript.DateTime(9999, 12, 31, 23, 59, 59, 999);

/// <summary>Represents the smallest possible value of DateTime. This field is read-only.</summary>
JavaScript.DateTime.MinValue = new JavaScript.DateTime(1753, 1, 1, 0, 0, 0, 0);

/// <summary>Gets a DateTime object that is set to the current date and time on this computer, expressed as the local time.</summary>
/// <returns>A DateTime whose value is the current local date and time.</returns>
JavaScript.DateTime.Now = function() {
    var d = new Date();
    return new DateTime(d.getFullYear(), d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
};

/// <summary>Gets the current date.</summary>
/// <returns>A DateTime set to today's date, with the time component set to 00:00:00.</returns>
JavaScript.DateTime.Today = function() {
    var d = new Date();
    return new DateTime(d.getFullYear(), d.getMonth() + 1, d.getDate());
};

/// <summary>Specifies the DateTime formats for conveting dates into strings.</summary>
JavaScript.DateTimeFormats = DateTimeFormats = {
    FullDateLongTime: 'F', 'F': '{0}, {1} {2}, {3} {4}:{5}:{6} {7}',
    FullDateShortTime: 'f', 'f': '{0}, {1} {2}, {3} {4}:{5} {6}',
    GeneralDateLongTime: 'G', 'G': '{0}/{1}/{2} {3}:{4}:{5} {6}',
    GeneralDateShortTime: 'g', 'g': '{0}/{1}/{2} {3}:{4} {5}',
    LongDate: 'D', 'D': '{0}, {1} {2}, {3}',
    LongTime: 'T', 'T': '{0}:{1}:{2} {3}',
    Month: 'M', 'M': '{0} {1}',
    RFC1123: 'R', 'R': '',
    ShortDate: 'd', 'd': '{0}/{1}/{2}',
    ShortTime: 't', 't': '{0}:{1} {2}',
    Sortable: 's', 's': '{0}-{1}-{2}T{3}:{4}:{5}',
    UniversalSortable: 'U', 'U': '{0}, {1} {2}, {3} {4}:{5}:{6} {7}',
    UniversalSortableInvariant: 'u', 'u': '{0}-{1}-{2} {3}:{4}:{5}Z',
    Year: 'Y', 'Y': '{0}, {1}'
};

/// <summary>The exception that is thrown when the format of an argument does not meet the parameter specifications of the invoked method.</summary>
JavaScript.FormatException = FormatException = function(object) {
    base = new Error(object);
    return base;
};

JavaScript.Int32 = Int32 = Number;

JavaScript.Int32.prototype.Equals = function(object) {
    return this == object;
};

JavaScript.Int32.NotANumber = function(object) {
    return isNaN(object);
};

JavaScript.Int32.Parse = function(value, radix) {
    return new Int32(parseInt(value, radix || 10));
};

JavaScript.Int32.TryParse = function(value, radix) {
    return !Int32.NotANumber(Int32.Parse(value, radix));
};

/// <summary>Specifies the month of the year.</summary>
JavaScript.MonthOfYear = MonthOfYear = {
    January: 1, '1': 'January',
    February: 2, '2': 'February',
    March: 3, '3': 'March',
    April: 4, '4': 'April',
    May: 5, '5': 'May',
    June: 6, '6': 'June',
    July: 7, '7': 'July',
    August: 8, '8': 'August',
    September: 9, '9': 'September',
    October: 10, '10': 'October',
    November: 11, '11': 'November',
    December: 12, '12': 'December'
};

/// <summary>Represents text as a series of Unicode characters.</summary>
JavaScript.String = String;

/// <summary>Compares substrings of two specified String objects, ignoring or honoring their case.</summary>
/// <param name="strA">The first string.</param>
/// <param name="strB">The second string.</param>
/// <param name="ignoreCase">
///   A boolean indicating a case-sensitive or insensitive comparison. (true indicates a case-insensitive comparison.)
/// </param>
/// <returns>
///   An integer indicating the lexical relationship between the two comparands.Value Condition Less than zero The
///   substring in strA is less than the substring in strB. Zero The substrings are equal, or length is zero. Greater
///   than zero The substring in strA is greater than the substring in strB.
/// </returns>
/// <exception cref="JavaScript.ArgumentNullException">strA or strB is null.</exception>
/// <exception cref="JavaScript.ArgumentOutOfRangeException">
///   indexA is greater than strA. Length. -or- indexB is greater than strB. Length. -or- indexA, indexB, or length is negative.
/// </exception>
JavaScript.String.Compare = function() {
    var stringX = arguments[0] || null,
            indexX = (arguments.length > 3 ? arguments[1] : 0),
            lengthX = (arguments.length >= 6 ? arguments[2] : (arguments.length <= 3 ? stringX.length : null));
    var stringY = (arguments.length == 2 ? arguments[1] : (arguments.length == 4 ? arguments[2] : arguments[3])) || null,
            indexY = (arguments.length == 4 ? arguments[3] : arguments[4]) || 0,
            lengthY = (arguments.length >= 6 ? arguments[5] : stringY.length);
    var options = (arguments.length == 3 ? arguments[2] : (arguments.length == 5 ? arguments[4] : arguments[6])) || JavaScript.CompareOptions.None;

    if (String.IsNullOrEmpty(stringX)) throw ("ArgumentNullException");
    if (String.IsNullOrEmpty(stringY)) throw ("ArgumentNullException");
    if ((indexX < 0 || indexX > stringX.length) || (indexY < 0 || indexY > stringY.length)) throw ("ArgumentOutOfRangeException");
    if ((lengthX < 0 || lengthX > stringX.length) || (lengthY < 0 || lengthY > stringY.length)) throw ("ArgumentOutOfRangeException");
    if ((indexX + lengthX) > stringX.length || (indexY + lengthY) > stringY.length) throw ("ArgumentOutOfRangeException");

    stringX = stringX.substring(indexX, (lengthX != null ? lengthX : lengthY) + indexX);
    stringY = stringY.substring(indexY, lengthY + indexY);

    if (options == JavaScript.CompareOptions.IgnoreCase || options == JavaScript.CompareOptions.OrdinalIgnoreCase) {
        stringX = stringX.toLowerCase();
        stringY = stringY.toLowerCase();
    };

    return (stringX == stringY ? 0 : (stringX < stringY ? -1 : 1));
};

JavaScript.String.prototype.CompareTo = function(value) {
    if (String.IsNullOrEmpty(value)) throw new JavaScript.ArgumentNullException("value");
    return String.Compare(this, value);
};

JavaScript.String.prototype.Contains = function(value) {
    if (String.IsNullOrEmpty(value)) throw new JavaScript.ArgumentNullExcepion("value");
    return this.IndexOf(value) > -1;
};

/// <summary>Determines whether the end of this string matches the specified string</summary>
/// <param name="value">a string object to compare to.</param>
/// <param name="ignoreCase">true to ignore case when comparing this instance and value; otherwise, false.</param>
/// <returns>true if the value parameter matches the end of this string; otherwise, false;</returns>
/// <exception cref="JavaScript.ArgumentNullException">value is null.</exception>
JavaScript.String.prototype.EndsWith = function(value, ignoreCase) {
    if (String.IsNullOrEmpty(value)) throw new JavaScript.ArgumentNullExcepion("value");
    return String.Compare(this.substr(this.length - value.length), value, ignoreCase || false) === 0;
};

JavaScript.String.prototype.Equals = function(value) {
    if (String.IsNullOrEmpty(value)) throw new JavaScript.ArgumentNullException("value");
    return String.Compare(this, value) == 0;
};

/// <summary>
///   Replaces the format item in a specified String with the text equivalent of the value of all specified Object instances.
/// </summary>
/// <param name="format">A String containing zero or more format items.</param>
/// <param name="args">The remaining arguments are the objects to format.</param>
/// <returns>
///   A copy of format in which all format items have been replaced by the String equivalents of the remaining arguments.
/// </returns>
/// <exception cref="JavaScript.FormatException">
///   format is invalid.-or- The number indicating an argument to format is less than zero, or greater than or equal to
///   the number of specified objects to format.
/// </exception>
/// <exception cref="JavaScript.ArgumentNullException">format is null.</exception>
JavaScript.String.Format = function(format) {
    if (String.IsNullOrEmpty(format)) throw new JavaScript.ArgumentNullException("format");
    if (format.match(/\{[0-9]+\}/g).length > arguments.length - 1) throw new JavaScript.FormatException("format");

    for (var i = 1; i < arguments.length; i++) {
        var regex = new RegExp('\\{' + (i - 1) + '\\}', 'g');
        format = format.replace(regex, arguments[i].toString());
    };

    return format;
};

/// <summary>
///   Reports the index of the first occurrence of the specified String in this instance. The search starts at a
///   specified character position and examines a specified number of character positions.
/// </summary>
/// <param name="value">The String to seek.</param>
/// <param name="startIndex">The search starting position.</param>
/// <param name="count">The number of character positions to examine.</param>
/// <returns>
///   The index position of value if that string is found, or -1 if it is not. If value is Empty, the return value is startIndex.
/// </returns>
/// <exception cref="JavaScript.ArgumentNullException">value is null.</exception>
/// <exception cref="JavaScript.ArgumentOutOfRangeException">
///   count or startIndex is negative. -or- count plus startIndex specify a
///   position that is not within this instance.
/// </exception>
JavaScript.String.prototype.IndexOf = function(value, startIndex, count, ignoreCase) {
    var startIndex = startIndex || 0, count = count || value.length;
    if (String.IsNullOrEmpty(value)) {
        if (value == null) throw new JavaScript.ArgumentNullException("value");
        return startIndex;
    };
    if (startIndex < 0 || startIndex > this.length) throw new JavaScript.ArgumentOutOfRangeException("startIndex");
    if (count < 0 || count > (this.length - startIndex) || count > value.length) throw new JavaScript.ArgumentOutOfRangeException("count");

    while ((startIndex + count) <= this.length) {
        if (String.Compare(this.substring(startIndex, startIndex + count), value.substring(0, count), ignoreCase || false) === 0) return startIndex;
        startIndex++;
    };
    return -1;
};

/// <summary>Indicates whether the specified String object is null or an Empty string.</summary>
/// <param name="value">A string reference.</param>
/// <returns>true if the value parameter is null or an empty string (""); otherwise, false.</returns>
JavaScript.String.IsNullOrEmpty = function(value) {
    return (value == null || value == "");
};

JavaScript.String.PadLeft = function(value, totalWidth, paddingChar) {
    paddingChar = paddingChar || ' ';

    while (value.length < totalWidth) {
        value = paddingChar + value;
    }

    return value.substr(value.length - totalWidth);
}

/// <summary>Determines whether the start of this string matches the specified string</summary>
/// <param name="value">a string object to compare to.</param>
/// <param name="ignoreCase">true to ignore case when comparing this instance and value; otherwise, false.</param>
/// <returns>true if the value parameter matches the start of this string; otherwise, false;</returns>
/// <exception cref="JavaScript.ArgumentNullException">value is null.</exception>
JavaScript.String.prototype.StartsWith = function(value, ignoreCase) {
    if (String.IsNullOrEmpty(value)) throw new JavaScript.ArgumentNullExcepion("value");
    return String.Compare(this.substring(0, value.length), value, ignoreCase || false) === 0;
};
