summaryrefslogtreecommitdiff
path: root/src/mscorlib/corefx
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/corefx')
-rw-r--r--src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs11
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs33
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs26
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs79
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs37
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs17
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs31
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs52
-rw-r--r--src/mscorlib/corefx/SR.cs247
-rw-r--r--src/mscorlib/corefx/System/Globalization/Calendar.cs854
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs341
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs469
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarData.cs381
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs19
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs413
-rw-r--r--src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs339
-rw-r--r--src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs1222
-rw-r--r--src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs399
-rw-r--r--src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs315
-rw-r--r--src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs395
-rw-r--r--src/mscorlib/corefx/System/Globalization/CompareInfo.cs925
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs304
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs561
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.cs2174
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs31
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs53
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.cs1144
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs104
-rw-r--r--src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs2958
-rw-r--r--src/mscorlib/corefx/System/Globalization/DateTimeFormatInfoScanner.cs742
-rw-r--r--src/mscorlib/corefx/System/Globalization/DayLightTime.cs56
-rw-r--r--src/mscorlib/corefx/System/Globalization/EastAsianLunisolarCalendar.cs719
-rw-r--r--src/mscorlib/corefx/System/Globalization/GregorianCalendar.cs662
-rw-r--r--src/mscorlib/corefx/System/Globalization/GregorianCalendarHelper.cs668
-rw-r--r--src/mscorlib/corefx/System/Globalization/GregorianCalendarTypes.cs21
-rw-r--r--src/mscorlib/corefx/System/Globalization/HebrewCalendar.cs1123
-rw-r--r--src/mscorlib/corefx/System/Globalization/HebrewNumber.cs465
-rw-r--r--src/mscorlib/corefx/System/Globalization/HijriCalendar.Unix.cs15
-rw-r--r--src/mscorlib/corefx/System/Globalization/HijriCalendar.Windows.cs16
-rw-r--r--src/mscorlib/corefx/System/Globalization/HijriCalendar.cs675
-rw-r--r--src/mscorlib/corefx/System/Globalization/InternalGlobalizationHelper.cs50
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Unix.cs91
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Windows.cs62
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseCalendar.cs413
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseLunisolarCalendar.cs311
-rw-r--r--src/mscorlib/corefx/System/Globalization/JulianCalendar.cs452
-rw-r--r--src/mscorlib/corefx/System/Globalization/KoreanCalendar.cs264
-rw-r--r--src/mscorlib/corefx/System/Globalization/KoreanLunisolarCalendar.cs1329
-rw-r--r--src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs819
-rw-r--r--src/mscorlib/corefx/System/Globalization/PersianCalendar.cs613
-rw-r--r--src/mscorlib/corefx/System/Globalization/RegionInfo.cs324
-rw-r--r--src/mscorlib/corefx/System/Globalization/STUBS.cs180
-rw-r--r--src/mscorlib/corefx/System/Globalization/StringInfo.cs322
-rw-r--r--src/mscorlib/corefx/System/Globalization/TaiwanCalendar.cs282
-rw-r--r--src/mscorlib/corefx/System/Globalization/TaiwanLunisolarCalendar.cs330
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextElementEnumerator.cs154
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs127
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.Windows.cs121
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.cs457
-rw-r--r--src/mscorlib/corefx/System/Globalization/ThaiBuddhistCalendar.cs233
-rw-r--r--src/mscorlib/corefx/System/Globalization/TimeSpanStyles.cs13
-rw-r--r--src/mscorlib/corefx/System/Globalization/UmAlQuraCalendar.cs862
-rw-r--r--src/mscorlib/corefx/System/Globalization/UnicodeCategory.cs70
63 files changed, 26975 insertions, 0 deletions
diff --git a/src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs b/src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs
new file mode 100644
index 0000000000..f8c5b26e44
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal static partial class Interop
+{
+ private static partial class Libraries
+ {
+ internal const string GlobalizationInterop = "System.Globalization.Native"; // CoreFX wrappers for ICU
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
new file mode 100644
index 0000000000..7b3caeabdd
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ internal delegate void EnumCalendarInfoCallback(
+ [MarshalAs(UnmanagedType.LPWStr)] string calendarString,
+ IntPtr context);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendars")]
+ internal static extern int GetCalendars(string localeName, CalendarId[] calendars, int calendarsCapacity);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendarInfo")]
+ internal static extern ResultCode GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType calendarDataType, [Out] StringBuilder result, int resultCapacity);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EnumCalendarInfo")]
+ internal static extern bool EnumCalendarInfo(EnumCalendarInfoCallback callback, string localeName, CalendarId calendarId, CalendarDataType calendarDataType, IntPtr context);
+
+ [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetLatestJapaneseEra")]
+ internal static extern int GetLatestJapaneseEra();
+
+ [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetJapaneseEraStartDate")]
+ internal static extern bool GetJapaneseEraStartDate(int era, out int startYear, out int startMonth, out int startDay);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
new file mode 100644
index 0000000000..115a8393be
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCase")]
+ internal unsafe static extern void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseInvariant")]
+ internal unsafe static extern void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseTurkish")]
+ internal unsafe static extern void ChangeCaseTurkish(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
new file mode 100644
index 0000000000..6acf55e17b
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Security;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortHandle")]
+ internal unsafe static extern SafeSortHandle GetSortHandle(byte[] localeName);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CloseSortHandle")]
+ internal unsafe static extern void CloseSortHandle(IntPtr handle);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareString")]
+ internal unsafe static extern int CompareString(SafeSortHandle sortHandle, char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")]
+ internal unsafe static extern int IndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")]
+ internal unsafe static extern int LastIndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")]
+ internal unsafe static extern int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool StartsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool EndsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")]
+ internal unsafe static extern int GetSortKey(SafeSortHandle sortHandle, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareStringOrdinalIgnoreCase")]
+ internal unsafe static extern int CompareStringOrdinalIgnoreCase(char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len);
+
+ [SecurityCritical]
+ internal class SafeSortHandle : SafeHandle
+ {
+ private SafeSortHandle() :
+ base(IntPtr.Zero, true)
+ {
+ }
+
+ public override bool IsInvalid
+ {
+ [SecurityCritical]
+ get { return handle == IntPtr.Zero; }
+ }
+
+ [SecurityCritical]
+ protected override bool ReleaseHandle()
+ {
+ CloseSortHandle(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
new file mode 100644
index 0000000000..3912581c73
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleName")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleName(string localeName, [Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoString")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleInfoString(string localeName, uint localeStringData, [Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetDefaultLocaleName")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoInt")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleInfoInt(string localeName, uint localeNumberData, ref int value);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoGroupingSizes")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleInfoGroupingSizes(string localeName, uint localeGroupingData, ref int primaryGroupSize, ref int secondaryGroupSize);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
new file mode 100644
index 0000000000..4621580063
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ // needs to be kept in sync with ResultCode in System.Globalization.Native
+ internal enum ResultCode
+ {
+ Success = 0,
+ UnknownError = 1,
+ InsufficentBuffer = 2,
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
new file mode 100644
index 0000000000..26a9fe0579
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Ansi, EntryPoint = "GlobalizationNative_ReadLink")] // readlink requires char*
+ internal static extern bool ReadLink(string filePath, [Out] StringBuilder result, uint resultCapacity);
+
+ // needs to be kept in sync with TimeZoneDisplayNameType in System.Globalization.Native
+ internal enum TimeZoneDisplayNameType
+ {
+ Generic = 0,
+ Standard = 1,
+ DaylightSavings = 2,
+ }
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetTimeZoneDisplayName")]
+ internal static extern ResultCode GetTimeZoneDisplayName(
+ string localeName,
+ string timeZoneId,
+ TimeZoneDisplayNameType type,
+ [Out] StringBuilder result,
+ int resultLength);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
new file mode 100644
index 0000000000..33b10c0d74
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+
+internal static partial class Interop
+{
+ /// <summary>
+ /// Helper for making interop calls that return a string, but we don't know
+ /// the correct size of buffer to make. So invoke the interop call with an
+ /// increasing buffer until the size is big enough.
+ /// </summary>
+ internal static bool CallStringMethod<TArg1, TArg2, TArg3>(
+ Func<TArg1, TArg2, TArg3, StringBuilder, GlobalizationInterop.ResultCode> interopCall,
+ TArg1 arg1,
+ TArg2 arg2,
+ TArg3 arg3,
+ out string result)
+ {
+ const int initialStringSize = 80;
+ const int maxDoubleAttempts = 5;
+
+ StringBuilder stringBuilder = StringBuilderCache.Acquire(initialStringSize);
+
+ for (int i = 0; i < maxDoubleAttempts; i++)
+ {
+ GlobalizationInterop.ResultCode resultCode = interopCall(arg1, arg2, arg3, stringBuilder);
+
+ if (resultCode == GlobalizationInterop.ResultCode.Success)
+ {
+ result = StringBuilderCache.GetStringAndRelease(stringBuilder);
+ return true;
+ }
+ else if (resultCode == GlobalizationInterop.ResultCode.InsufficentBuffer)
+ {
+ // increase the string size and loop
+ stringBuilder.EnsureCapacity(stringBuilder.Capacity * 2);
+ }
+ else
+ {
+ // if there is an unknown error, don't proceed
+ break;
+ }
+ }
+
+ StringBuilderCache.Release(stringBuilder);
+ result = null;
+ return false;
+ }
+}
diff --git a/src/mscorlib/corefx/SR.cs b/src/mscorlib/corefx/SR.cs
new file mode 100644
index 0000000000..513bd9d94d
--- /dev/null
+++ b/src/mscorlib/corefx/SR.cs
@@ -0,0 +1,247 @@
+using System;
+
+namespace System.Globalization
+{
+ internal static class SR
+ {
+ public static string Arg_HexStyleNotSupported
+ {
+ get { return Environment.GetResourceString("Arg_HexStyleNotSupported"); }
+ }
+
+ public static string Arg_InvalidHexStyle
+ {
+ get { return Environment.GetResourceString("Arg_InvalidHexStyle"); }
+ }
+
+ public static string ArgumentNull_Array
+ {
+ get { return Environment.GetResourceString("ArgumentNull_Array"); }
+ }
+
+ public static string ArgumentNull_ArrayValue
+ {
+ get { return Environment.GetResourceString("ArgumentNull_ArrayValue"); }
+ }
+
+ public static string ArgumentNull_Obj
+ {
+ get { return Environment.GetResourceString("ArgumentNull_Obj"); }
+ }
+
+ public static string ArgumentNull_String
+ {
+ get { return Environment.GetResourceString("ArgumentNull_String"); }
+ }
+
+ public static string ArgumentOutOfRange_AddValue
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_AddValue"); }
+ }
+
+ public static string ArgumentOutOfRange_BadHourMinuteSecond
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond"); }
+ }
+
+ public static string ArgumentOutOfRange_BadYearMonthDay
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"); }
+ }
+
+ public static string ArgumentOutOfRange_Bounds_Lower_Upper
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper"); }
+ }
+
+ public static string ArgumentOutOfRange_CalendarRange
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_CalendarRange"); }
+ }
+
+ public static string ArgumentOutOfRange_Count
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Count"); }
+ }
+
+ public static string ArgumentOutOfRange_Day
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Day"); }
+ }
+
+ public static string ArgumentOutOfRange_Enum
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Enum"); }
+ }
+
+ public static string ArgumentOutOfRange_Era
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Era"); }
+ }
+
+ public static string ArgumentOutOfRange_Index
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Index"); }
+ }
+
+ public static string ArgumentOutOfRange_InvalidEraValue
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"); }
+ }
+
+ public static string ArgumentOutOfRange_Month
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Month"); }
+ }
+
+ public static string ArgumentOutOfRange_NeedNonNegNum
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"); }
+ }
+
+ public static string ArgumentOutOfRange_NeedPosNum
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"); }
+ }
+
+ public static string ArgumentOutOfRange_OffsetLength
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"); }
+ }
+
+ public static string ArgumentOutOfRange_Range
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Range"); }
+ }
+
+ public static string Argument_CompareOptionOrdinal
+ {
+ get { return Environment.GetResourceString("Argument_CompareOptionOrdinal"); }
+ }
+
+ public static string Argument_ConflictingDateTimeRoundtripStyles
+ {
+ get { return Environment.GetResourceString("Argument_ConflictingDateTimeRoundtripStyles"); }
+ }
+
+ public static string Argument_ConflictingDateTimeStyles
+ {
+ get { return Environment.GetResourceString("Argument_ConflictingDateTimeStyles"); }
+ }
+
+ public static string Argument_CultureInvalidIdentifier
+ {
+ get { return Environment.GetResourceString("Argument_CultureInvalidIdentifier"); }
+ }
+
+ public static string Argument_CultureNotSupported
+ {
+ get { return Environment.GetResourceString("Argument_CultureNotSupported"); }
+ }
+
+ public static string Argument_EmptyDecString
+ {
+ get { return Environment.GetResourceString("Argument_EmptyDecString"); }
+ }
+
+ public static string Argument_InvalidArrayLength
+ {
+ get { return Environment.GetResourceString("Argument_InvalidArrayLength"); }
+ }
+
+ public static string Argument_InvalidCalendar
+ {
+ get { return Environment.GetResourceString("Argument_InvalidCalendar"); }
+ }
+
+ public static string Argument_InvalidCultureName
+ {
+ get { return Environment.GetResourceString("Argument_InvalidCultureName"); }
+ }
+
+ public static string Argument_InvalidDateTimeStyles
+ {
+ get { return Environment.GetResourceString("Argument_InvalidDateTimeStyles"); }
+ }
+
+ public static string Argument_InvalidFlag
+ {
+ get { return Environment.GetResourceString("Argument_InvalidFlag"); }
+ }
+
+ public static string Argument_InvalidGroupSize
+ {
+ get { return Environment.GetResourceString("Argument_InvalidGroupSize"); }
+ }
+
+ public static string Argument_InvalidNeutralRegionName
+ {
+ get { return Environment.GetResourceString("Argument_InvalidNeutralRegionName"); }
+ }
+
+ public static string Argument_InvalidNumberStyles
+ {
+ get { return Environment.GetResourceString("Argument_InvalidNumberStyles"); }
+ }
+
+ public static string Argument_InvalidResourceCultureName
+ {
+ get { return Environment.GetResourceString("Argument_InvalidResourceCultureName"); }
+ }
+
+ public static string Argument_NoEra
+ {
+ get { return Environment.GetResourceString("Argument_NoEra"); }
+ }
+
+ public static string Argument_NoRegionInvariantCulture
+ {
+ get { return Environment.GetResourceString("Argument_NoRegionInvariantCulture"); }
+ }
+
+ public static string Argument_ResultCalendarRange
+ {
+ get { return Environment.GetResourceString("Argument_ResultCalendarRange"); }
+ }
+
+ public static string Format_BadFormatSpecifier
+ {
+ get { return Environment.GetResourceString("Format_BadFormatSpecifier"); }
+ }
+
+ public static string InvalidOperation_DateTimeParsing
+ {
+ get { return Environment.GetResourceString("InvalidOperation_DateTimeParsing"); }
+ }
+
+ public static string InvalidOperation_EnumEnded
+ {
+ get { return Environment.GetResourceString("InvalidOperation_EnumEnded"); }
+ }
+
+ public static string InvalidOperation_EnumNotStarted
+ {
+ get { return Environment.GetResourceString("InvalidOperation_EnumNotStarted"); }
+ }
+
+ public static string InvalidOperation_ReadOnly
+ {
+ get { return Environment.GetResourceString("InvalidOperation_ReadOnly"); }
+ }
+
+ public static string Overflow_TimeSpanTooLong
+ {
+ get { return Environment.GetResourceString("Overflow_TimeSpanTooLong"); }
+ }
+
+ public static string Serialization_MemberOutOfRange
+ {
+ get { return Environment.GetResourceString("Serialization_MemberOutOfRange"); }
+ }
+
+ public static string Format(string formatString, params object[] args)
+ {
+ return string.Format(CultureInfo.CurrentCulture, formatString, args);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/Calendar.cs b/src/mscorlib/corefx/System/Globalization/Calendar.cs
new file mode 100644
index 0000000000..343682d156
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/Calendar.cs
@@ -0,0 +1,854 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Globalization;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ // This abstract class represents a calendar. A calendar reckons time in
+ // divisions such as weeks, months and years. The number, length and start of
+ // the divisions vary in each calendar.
+ //
+ // Any instant in time can be represented as an n-tuple of numeric values using
+ // a particular calendar. For example, the next vernal equinox occurs at (0.0, 0
+ // , 46, 8, 20, 3, 1999) in the Gregorian calendar. An implementation of
+ // Calendar can map any DateTime value to such an n-tuple and vice versa. The
+ // DateTimeFormat class can map between such n-tuples and a textual
+ // representation such as "8:46 AM March 20th 1999 AD".
+ //
+ // Most calendars identify a year which begins the current era. There may be any
+ // number of previous eras. The Calendar class identifies the eras as enumerated
+ // integers where the current era (CurrentEra) has the value zero.
+ //
+ // For consistency, the first unit in each interval, e.g. the first month, is
+ // assigned the value one.
+ // The calculation of hour/minute/second is moved to Calendar from GregorianCalendar,
+ // since most of the calendars (or all?) have the same way of calcuating hour/minute/second.
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public abstract partial class Calendar : ICloneable
+ {
+ // Number of 100ns (10E-7 second) ticks per time unit
+ internal const long TicksPerMillisecond = 10000;
+ internal const long TicksPerSecond = TicksPerMillisecond * 1000;
+ internal const long TicksPerMinute = TicksPerSecond * 60;
+ internal const long TicksPerHour = TicksPerMinute * 60;
+ internal const long TicksPerDay = TicksPerHour * 24;
+
+ // Number of milliseconds per time unit
+ internal const int MillisPerSecond = 1000;
+ internal const int MillisPerMinute = MillisPerSecond * 60;
+ internal const int MillisPerHour = MillisPerMinute * 60;
+ internal const int MillisPerDay = MillisPerHour * 24;
+
+ // Number of days in a non-leap year
+ internal const int DaysPerYear = 365;
+ // Number of days in 4 years
+ internal const int DaysPer4Years = DaysPerYear * 4 + 1;
+ // Number of days in 100 years
+ internal const int DaysPer100Years = DaysPer4Years * 25 - 1;
+ // Number of days in 400 years
+ internal const int DaysPer400Years = DaysPer100Years * 4 + 1;
+
+ // Number of days from 1/1/0001 to 1/1/10000
+ internal const int DaysTo10000 = DaysPer400Years * 25 - 366;
+
+ internal const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
+
+
+ private int _currentEraValue = -1;
+
+ [OptionalField(VersionAdded = 2)]
+ private bool _isReadOnly = false;
+
+#if INSIDE_CLR
+ internal const CalendarId CAL_HEBREW = CalendarId.HEBREW;
+ internal const CalendarId CAL_HIJRI = CalendarId.HIJRI;
+ internal const CalendarId CAL_JAPAN = CalendarId.JAPAN;
+ internal const CalendarId CAL_JULIAN = CalendarId.JULIAN;
+ internal const CalendarId CAL_TAIWAN = CalendarId.TAIWAN;
+ internal const CalendarId CAL_UMALQURA = CalendarId.UMALQURA;
+ internal const CalendarId CAL_PERSIAN = CalendarId.PERSIAN;
+#endif
+
+ // The minimum supported DateTime range for the calendar.
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MinValue);
+ }
+ }
+
+ // The maximum supported DateTime range for the calendar.
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+
+
+
+ protected Calendar()
+ {
+ //Do-nothing constructor.
+ }
+
+ ///
+ // This can not be abstract, otherwise no one can create a subclass of Calendar.
+ //
+ internal virtual CalendarId ID
+ {
+ get
+ {
+ return CalendarId.UNINITIALIZED_VALUE;
+ }
+ }
+
+ ///
+ // Return the Base calendar ID for calendars that didn't have defined data in calendarData
+ //
+
+ internal virtual CalendarId BaseCalendarID
+ {
+ get { return ID; }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsReadOnly
+ //
+ // Detect if the object is readonly.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public bool IsReadOnly
+ {
+ get { return (_isReadOnly); }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Clone
+ //
+ // Is the implementation of ICloneable.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual object Clone()
+ {
+ object o = MemberwiseClone();
+ ((Calendar)o).SetReadOnlyState(false);
+ return (o);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ReadOnly
+ //
+ // Create a cloned readonly instance or return the input one if it is
+ // readonly.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ internal static Calendar ReadOnly(Calendar calendar)
+ {
+ if (calendar == null) { throw new ArgumentNullException("calendar"); }
+ Contract.EndContractBlock();
+ if (calendar.IsReadOnly) { return (calendar); }
+
+ Calendar clonedCalendar = (Calendar)(calendar.MemberwiseClone());
+ clonedCalendar.SetReadOnlyState(true);
+
+ return (clonedCalendar);
+ }
+
+ internal void VerifyWritable()
+ {
+ if (_isReadOnly)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+ }
+
+ internal void SetReadOnlyState(bool readOnly)
+ {
+ _isReadOnly = readOnly;
+ }
+
+
+ /*=================================CurrentEraValue==========================
+ **Action: This is used to convert CurretEra(0) to an appropriate era value.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ **Notes:
+ ** The value is from calendar.nlp.
+ ============================================================================*/
+
+ internal virtual int CurrentEraValue
+ {
+ get
+ {
+ // The following code assumes that the current era value can not be -1.
+ if (_currentEraValue == -1)
+ {
+ Contract.Assert(BaseCalendarID != CalendarId.UNINITIALIZED_VALUE, "[Calendar.CurrentEraValue] Expected a real calendar ID");
+ _currentEraValue = CalendarData.GetCalendarData(BaseCalendarID).iCurrentEra;
+ }
+ return (_currentEraValue);
+ }
+ }
+
+ // The current era for a calendar.
+
+ public const int CurrentEra = 0;
+
+ internal int twoDigitYearMax = -1;
+
+ internal static void CheckAddResult(long ticks, DateTime minValue, DateTime maxValue)
+ {
+ if (ticks < minValue.Ticks || ticks > maxValue.Ticks)
+ {
+ throw new ArgumentException(
+ String.Format(CultureInfo.InvariantCulture, SR.Format(SR.Argument_ResultCalendarRange,
+ minValue, maxValue)));
+ }
+ Contract.EndContractBlock();
+ }
+
+ internal DateTime Add(DateTime time, double value, int scale)
+ {
+ // From ECMA CLI spec, Partition III, section 3.27:
+ //
+ // If overflow occurs converting a floating-point type to an integer, or if the floating-point value
+ // being converted to an integer is a NaN, the value returned is unspecified.
+ //
+ // Based upon this, this method should be performing the comparison against the double
+ // before attempting a cast. Otherwise, the result is undefined.
+ double tempMillis = (value * scale + (value >= 0 ? 0.5 : -0.5));
+ if (!((tempMillis > -(double)MaxMillis) && (tempMillis < (double)MaxMillis)))
+ {
+ throw new ArgumentOutOfRangeException("value", SR.ArgumentOutOfRange_AddValue);
+ }
+
+ long millis = (long)tempMillis;
+ long ticks = time.Ticks + millis * TicksPerMillisecond;
+ CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // milliseconds to the specified DateTime. The result is computed by rounding
+ // the number of milliseconds given by value to the nearest integer,
+ // and adding that interval to the specified DateTime. The value
+ // argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddMilliseconds(DateTime time, double milliseconds)
+ {
+ return (Add(time, milliseconds, 1));
+ }
+
+
+ // Returns the DateTime resulting from adding a fractional number of
+ // days to the specified DateTime. The result is computed by rounding the
+ // fractional number of days given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddDays(DateTime time, int days)
+ {
+ return (Add(time, days, MillisPerDay));
+ }
+
+ // Returns the DateTime resulting from adding a fractional number of
+ // hours to the specified DateTime. The result is computed by rounding the
+ // fractional number of hours given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddHours(DateTime time, int hours)
+ {
+ return (Add(time, hours, MillisPerHour));
+ }
+
+
+ // Returns the DateTime resulting from adding a fractional number of
+ // minutes to the specified DateTime. The result is computed by rounding the
+ // fractional number of minutes given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddMinutes(DateTime time, int minutes)
+ {
+ return (Add(time, minutes, MillisPerMinute));
+ }
+
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+ public abstract DateTime AddMonths(DateTime time, int months);
+
+ // Returns the DateTime resulting from adding a number of
+ // seconds to the specified DateTime. The result is computed by rounding the
+ // fractional number of seconds given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddSeconds(DateTime time, int seconds)
+ {
+ return Add(time, seconds, MillisPerSecond);
+ }
+
+ // Returns the DateTime resulting from adding a number of
+ // weeks to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddWeeks(DateTime time, int weeks)
+ {
+ return (AddDays(time, weeks * 7));
+ }
+
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+ public abstract DateTime AddYears(DateTime time, int years);
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+ public abstract int GetDayOfMonth(DateTime time);
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+ public abstract DayOfWeek GetDayOfWeek(DateTime time);
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+
+ public abstract int GetDayOfYear(DateTime time);
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+ public virtual int GetDaysInMonth(int year, int month)
+ {
+ return (GetDaysInMonth(year, month, CurrentEra));
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments for the specified era.
+ //
+
+ public abstract int GetDaysInMonth(int year, int month, int era);
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public virtual int GetDaysInYear(int year)
+ {
+ return (GetDaysInYear(year, CurrentEra));
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public abstract int GetDaysInYear(int year, int era);
+
+ // Returns the era for the specified DateTime value.
+
+ public abstract int GetEra(DateTime time);
+
+ /*=================================Eras==========================
+ **Action: Get the list of era values.
+ **Returns: The int array of the era names supported in this calendar.
+ ** null if era is not used.
+ **Arguments: None.
+ **Exceptions: None.
+ ============================================================================*/
+
+
+ public abstract int[] Eras
+ {
+ get;
+ }
+
+
+ // Returns the hour part of the specified DateTime. The returned value is an
+ // integer between 0 and 23.
+ //
+
+ public virtual int GetHour(DateTime time)
+ {
+ return ((int)((time.Ticks / TicksPerHour) % 24));
+ }
+
+ // Returns the millisecond part of the specified DateTime. The returned value
+ // is an integer between 0 and 999.
+ //
+
+ public virtual double GetMilliseconds(DateTime time)
+ {
+ return (double)((time.Ticks / TicksPerMillisecond) % 1000);
+ }
+
+ // Returns the minute part of the specified DateTime. The returned value is
+ // an integer between 0 and 59.
+ //
+
+ public virtual int GetMinute(DateTime time)
+ {
+ return ((int)((time.Ticks / TicksPerMinute) % 60));
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+ public abstract int GetMonth(DateTime time);
+
+ // Returns the number of months in the specified year in the current era.
+
+ public virtual int GetMonthsInYear(int year)
+ {
+ return (GetMonthsInYear(year, CurrentEra));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+ public abstract int GetMonthsInYear(int year, int era);
+
+ // Returns the second part of the specified DateTime. The returned value is
+ // an integer between 0 and 59.
+ //
+
+ public virtual int GetSecond(DateTime time)
+ {
+ return ((int)((time.Ticks / TicksPerSecond) % 60));
+ }
+
+ /*=================================GetFirstDayWeekOfYear==========================
+ **Action: Get the week of year using the FirstDay rule.
+ **Returns: the week of year.
+ **Arguments:
+ ** time
+ ** firstDayOfWeek the first day of week (0=Sunday, 1=Monday, ... 6=Saturday)
+ **Notes:
+ ** The CalendarWeekRule.FirstDay rule: Week 1 begins on the first day of the year.
+ ** Assume f is the specifed firstDayOfWeek,
+ ** and n is the day of week for January 1 of the specified year.
+ ** Assign offset = n - f;
+ ** Case 1: offset = 0
+ ** E.g.
+ ** f=1
+ ** weekday 0 1 2 3 4 5 6 0 1
+ ** date 1/1
+ ** week# 1 2
+ ** then week of year = (GetDayOfYear(time) - 1) / 7 + 1
+ **
+ ** Case 2: offset < 0
+ ** e.g.
+ ** n=1 f=3
+ ** weekday 0 1 2 3 4 5 6 0
+ ** date 1/1
+ ** week# 1 2
+ ** This means that the first week actually starts 5 days before 1/1.
+ ** So week of year = (GetDayOfYear(time) + (7 + offset) - 1) / 7 + 1
+ ** Case 3: offset > 0
+ ** e.g.
+ ** f=0 n=2
+ ** weekday 0 1 2 3 4 5 6 0 1 2
+ ** date 1/1
+ ** week# 1 2
+ ** This means that the first week actually starts 2 days before 1/1.
+ ** So Week of year = (GetDayOfYear(time) + offset - 1) / 7 + 1
+ ============================================================================*/
+
+ internal int GetFirstDayWeekOfYear(DateTime time, int firstDayOfWeek)
+ {
+ int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ // Calculate the day of week for the first day of the year.
+ // dayOfWeek - (dayOfYear % 7) is the day of week for the first day of this year. Note that
+ // this value can be less than 0. It's fine since we are making it positive again in calculating offset.
+ int dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
+ int offset = (dayForJan1 - firstDayOfWeek + 14) % 7;
+ Contract.Assert(offset >= 0, "Calendar.GetFirstDayWeekOfYear(): offset >= 0");
+ return ((dayOfYear + offset) / 7 + 1);
+ }
+
+ private int GetWeekOfYearFullDays(DateTime time, int firstDayOfWeek, int fullDays)
+ {
+ int dayForJan1;
+ int offset;
+ int day;
+
+ int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ //
+ // Calculate the number of days between the first day of year (1/1) and the first day of the week.
+ // This value will be a positive value from 0 ~ 6. We call this value as "offset".
+ //
+ // If offset is 0, it means that the 1/1 is the start of the first week.
+ // Assume the first day of the week is Monday, it will look like this:
+ // Sun Mon Tue Wed Thu Fri Sat
+ // 12/31 1/1 1/2 1/3 1/4 1/5 1/6
+ // +--> First week starts here.
+ //
+ // If offset is 1, it means that the first day of the week is 1 day ahead of 1/1.
+ // Assume the first day of the week is Monday, it will look like this:
+ // Sun Mon Tue Wed Thu Fri Sat
+ // 1/1 1/2 1/3 1/4 1/5 1/6 1/7
+ // +--> First week starts here.
+ //
+ // If offset is 2, it means that the first day of the week is 2 days ahead of 1/1.
+ // Assume the first day of the week is Monday, it will look like this:
+ // Sat Sun Mon Tue Wed Thu Fri Sat
+ // 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8
+ // +--> First week starts here.
+
+
+
+ // Day of week is 0-based.
+ // Get the day of week for 1/1. This can be derived from the day of week of the target day.
+ // Note that we can get a negative value. It's ok since we are going to make it a positive value when calculating the offset.
+ dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
+
+ // Now, calculate the offset. Subtract the first day of week from the dayForJan1. And make it a positive value.
+ offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
+ if (offset != 0 && offset >= fullDays)
+ {
+ //
+ // If the offset is greater than the value of fullDays, it means that
+ // the first week of the year starts on the week where Jan/1 falls on.
+ //
+ offset -= 7;
+ }
+ //
+ // Calculate the day of year for specified time by taking offset into account.
+ //
+ day = dayOfYear - offset;
+ if (day >= 0)
+ {
+ //
+ // If the day of year value is greater than zero, get the week of year.
+ //
+ return (day / 7 + 1);
+ }
+ //
+ // Otherwise, the specified time falls on the week of previous year.
+ // Call this method again by passing the last day of previous year.
+ //
+ // the last day of the previous year may "underflow" to no longer be a valid date time for
+ // this calendar if we just subtract so we need the subclass to provide us with
+ // that information
+ if (time <= MinSupportedDateTime.AddDays(dayOfYear))
+ {
+ return GetWeekOfYearOfMinSupportedDateTime(firstDayOfWeek, fullDays);
+ }
+ return (GetWeekOfYearFullDays(time.AddDays(-(dayOfYear + 1)), firstDayOfWeek, fullDays));
+ }
+
+ private int GetWeekOfYearOfMinSupportedDateTime(int firstDayOfWeek, int minimumDaysInFirstWeek)
+ {
+ int dayOfYear = GetDayOfYear(MinSupportedDateTime) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ int dayOfWeekOfFirstOfYear = (int)GetDayOfWeek(MinSupportedDateTime) - dayOfYear % 7;
+
+ // Calculate the offset (how many days from the start of the year to the start of the week)
+ int offset = (firstDayOfWeek + 7 - dayOfWeekOfFirstOfYear) % 7;
+ if (offset == 0 || offset >= minimumDaysInFirstWeek)
+ {
+ // First of year falls in the first week of the year
+ return 1;
+ }
+
+ int daysInYearBeforeMinSupportedYear = DaysInYearBeforeMinSupportedYear - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ int dayOfWeekOfFirstOfPreviousYear = dayOfWeekOfFirstOfYear - 1 - (daysInYearBeforeMinSupportedYear % 7);
+
+ // starting from first day of the year, how many days do you have to go forward
+ // before getting to the first day of the week?
+ int daysInInitialPartialWeek = (firstDayOfWeek - dayOfWeekOfFirstOfPreviousYear + 14) % 7;
+ int day = daysInYearBeforeMinSupportedYear - daysInInitialPartialWeek;
+ if (daysInInitialPartialWeek >= minimumDaysInFirstWeek)
+ {
+ // If the offset is greater than the minimum Days in the first week, it means that
+ // First of year is part of the first week of the year even though it is only a partial week
+ // add another week
+ day += 7;
+ }
+
+ return (day / 7 + 1);
+ }
+
+ // it would be nice to make this abstract but we can't since that would break previous implementations
+ protected virtual int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ return 365;
+ }
+ }
+
+
+ // Returns the week of year for the specified DateTime. The returned value is an
+ // integer between 1 and 53.
+ //
+
+ public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ if ((int)firstDayOfWeek < 0 || (int)firstDayOfWeek > 6)
+ {
+ throw new ArgumentOutOfRangeException(
+ "firstDayOfWeek", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ Contract.EndContractBlock();
+ switch (rule)
+ {
+ case CalendarWeekRule.FirstDay:
+ return (GetFirstDayWeekOfYear(time, (int)firstDayOfWeek));
+ case CalendarWeekRule.FirstFullWeek:
+ return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 7));
+ case CalendarWeekRule.FirstFourDayWeek:
+ return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 4));
+ }
+ throw new ArgumentOutOfRangeException(
+ "rule", SR.Format(SR.ArgumentOutOfRange_Range,
+ CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and 9999.
+ //
+
+ public abstract int GetYear(DateTime time);
+
+ // Checks whether a given day in the current era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public virtual bool IsLeapDay(int year, int month, int day)
+ {
+ return (IsLeapDay(year, month, day, CurrentEra));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public abstract bool IsLeapDay(int year, int month, int day, int era);
+
+ // Checks whether a given month in the current era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public virtual bool IsLeapMonth(int year, int month)
+ {
+ return (IsLeapMonth(year, month, CurrentEra));
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public abstract bool IsLeapMonth(int year, int month, int era);
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual int GetLeapMonth(int year, int era)
+ {
+ if (!IsLeapYear(year, era))
+ return 0;
+
+ int monthsCount = GetMonthsInYear(year, era);
+ for (int month = 1; month <= monthsCount; month++)
+ {
+ if (IsLeapMonth(year, month, era))
+ return month;
+ }
+
+ return 0;
+ }
+
+ // Checks whether a given year in the current era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public virtual bool IsLeapYear(int year)
+ {
+ return (IsLeapYear(year, CurrentEra));
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public abstract bool IsLeapYear(int year, int era);
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public virtual DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
+ {
+ return (ToDateTime(year, month, day, hour, minute, second, millisecond, CurrentEra));
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public abstract DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era);
+
+ internal virtual Boolean TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result)
+ {
+ result = DateTime.MinValue;
+ try
+ {
+ result = ToDateTime(year, month, day, hour, minute, second, millisecond, era);
+ return true;
+ }
+ catch (ArgumentException)
+ {
+ return false;
+ }
+ }
+
+ internal virtual bool IsValidYear(int year, int era)
+ {
+ return (year >= GetYear(MinSupportedDateTime) && year <= GetYear(MaxSupportedDateTime));
+ }
+
+ internal virtual bool IsValidMonth(int year, int month, int era)
+ {
+ return (IsValidYear(year, era) && month >= 1 && month <= GetMonthsInYear(year, era));
+ }
+
+ internal virtual bool IsValidDay(int year, int month, int day, int era)
+ {
+ return (IsValidMonth(year, month, era) && day >= 1 && day <= GetDaysInMonth(year, month, era));
+ }
+
+
+ // Returns and assigns the maximum value to represent a two digit year. This
+ // value is the upper boundary of a 100 year range that allows a two digit year
+ // to be properly translated to a four digit year. For example, if 2029 is the
+ // upper boundary, then a two digit value of 30 should be interpreted as 1930
+ // while a two digit value of 29 should be interpreted as 2029. In this example
+ // , the 100 year range would be from 1930-2029. See ToFourDigitYear().
+
+ public virtual int TwoDigitYearMax
+ {
+ get
+ {
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ twoDigitYearMax = value;
+ }
+ }
+
+ // Converts the year value to the appropriate century by using the
+ // TwoDigitYearMax property. For example, if the TwoDigitYearMax value is 2029,
+ // then a two digit value of 30 will get converted to 1930 while a two digit
+ // value of 29 will get converted to 2029.
+
+ public virtual int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+ if (year < 100)
+ {
+ return ((TwoDigitYearMax / 100 - (year > TwoDigitYearMax % 100 ? 1 : 0)) * 100 + year);
+ }
+ // If the year value is above 100, just return the year value. Don't have to do
+ // the TwoDigitYearMax comparison.
+ return (year);
+ }
+
+ // Return the tick count corresponding to the given hour, minute, second.
+ // Will check the if the parameters are valid.
+ internal static long TimeToTicks(int hour, int minute, int second, int millisecond)
+ {
+ if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60)
+ {
+ if (millisecond < 0 || millisecond >= MillisPerSecond)
+ {
+ throw new ArgumentOutOfRangeException(
+ "millisecond",
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1)));
+ }
+ return InternalGloablizationHelper.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond;
+ }
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+ }
+
+ internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue)
+ {
+ // Call nativeGetTwoDigitYearMax
+ int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID);
+ if (twoDigitYearMax < 0)
+ {
+ twoDigitYearMax = defaultYearValue;
+ }
+ return (twoDigitYearMax);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs b/src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs
new file mode 100644
index 0000000000..6c6a18ec37
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs
@@ -0,0 +1,341 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+namespace System.Globalization
+{
+ // needs to be kept in sync with CalendarDataType in System.Globalization.Native
+ internal enum CalendarDataType
+ {
+ Uninitialized = 0,
+ NativeName = 1,
+ MonthDay = 2,
+ ShortDates = 3,
+ LongDates = 4,
+ YearMonths = 5,
+ DayNames = 6,
+ AbbrevDayNames = 7,
+ MonthNames = 8,
+ AbbrevMonthNames = 9,
+ SuperShortDayNames = 10,
+ MonthGenitiveNames = 11,
+ AbbrevMonthGenitiveNames = 12,
+ EraNames = 13,
+ AbbrevEraNames = 14,
+ }
+
+ internal partial class CalendarData
+ {
+ private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId)
+ {
+ bool result = true;
+ result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName);
+ result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay);
+ this.sMonthDay = NormalizeDatePattern(this.sMonthDay);
+
+ result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.ShortDates, out this.saShortDates);
+ result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.LongDates, out this.saLongDates);
+ result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.YearMonths, out this.saYearMonths);
+ result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames);
+ result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames);
+ result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames);
+ result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames);
+ result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames);
+
+ return result;
+ }
+
+ internal static int GetTwoDigitYearMax(CalendarId calendarId)
+ {
+ // There is no user override for this value on Linux or in ICU.
+ // So just return -1 to use the hard-coded defaults.
+ return -1;
+ }
+
+ // Call native side to figure out which calendars are allowed
+ [SecuritySafeCritical]
+ internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars)
+ {
+ // NOTE: there are no 'user overrides' on Linux
+ int count = Interop.GlobalizationInterop.GetCalendars(localeName, calendars, calendars.Length);
+
+ // ensure there is at least 1 calendar returned
+ if (count == 0 && calendars.Length > 0)
+ {
+ calendars[0] = CalendarId.GREGORIAN;
+ count = 1;
+ }
+
+ return count;
+ }
+
+ private static bool SystemSupportsTaiwaneseCalendar()
+ {
+ return true;
+ }
+
+ // PAL Layer ends here
+
+ [SecuritySafeCritical]
+ private static bool GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string calendarString)
+ {
+ return Interop.CallStringMethod(
+ (locale, calId, type, stringBuilder) =>
+ Interop.GlobalizationInterop.GetCalendarInfo(
+ locale,
+ calId,
+ type,
+ stringBuilder,
+ stringBuilder.Capacity),
+ localeName,
+ calendarId,
+ dataType,
+ out calendarString);
+ }
+
+ private static bool EnumDatePatterns(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] datePatterns)
+ {
+ datePatterns = null;
+
+ CallbackContext callbackContext = new CallbackContext();
+ callbackContext.DisallowDuplicates = true;
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext);
+ if (result)
+ {
+ List<string> datePatternsList = callbackContext.Results;
+
+ datePatterns = new string[datePatternsList.Count];
+ for (int i = 0; i < datePatternsList.Count; i++)
+ {
+ datePatterns[i] = NormalizeDatePattern(datePatternsList[i]);
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// The ICU date format characters are not exactly the same as the .NET date format characters.
+ /// NormalizeDatePattern will take in an ICU date pattern and return the equivalent .NET date pattern.
+ /// </summary>
+ /// <remarks>
+ /// see Date Field Symbol Table in http://userguide.icu-project.org/formatparse/datetime
+ /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx
+ /// </remarks>
+ private static string NormalizeDatePattern(string input)
+ {
+ StringBuilder destination = StringBuilderCache.Acquire(input.Length);
+
+ int index = 0;
+ while (index < input.Length)
+ {
+ switch (input[index])
+ {
+ case '\'':
+ // single quotes escape characters, like 'de' in es-SP
+ // so read verbatim until the next single quote
+ destination.Append(input[index++]);
+ while (index < input.Length)
+ {
+ char current = input[index++];
+ destination.Append(current);
+ if (current == '\'')
+ {
+ break;
+ }
+ }
+ break;
+ case 'E':
+ case 'e':
+ case 'c':
+ // 'E' in ICU is the day of the week, which maps to 3 or 4 'd's in .NET
+ // 'e' in ICU is the local day of the week, which has no representation in .NET, but
+ // maps closest to 3 or 4 'd's in .NET
+ // 'c' in ICU is the stand-alone day of the week, which has no representation in .NET, but
+ // maps closest to 3 or 4 'd's in .NET
+ NormalizeDayOfWeek(input, destination, ref index);
+ break;
+ case 'L':
+ case 'M':
+ // 'L' in ICU is the stand-alone name of the month,
+ // which maps closest to 'M' in .NET since it doesn't support stand-alone month names in patterns
+ // 'M' in both ICU and .NET is the month,
+ // but ICU supports 5 'M's, which is the super short month name
+ int occurrences = CountOccurrences(input, input[index], ref index);
+ if (occurrences > 4)
+ {
+ // 5 'L's or 'M's in ICU is the super short name, which maps closest to MMM in .NET
+ occurrences = 3;
+ }
+ destination.Append('M', occurrences);
+ break;
+ case 'G':
+ // 'G' in ICU is the era, which maps to 'g' in .NET
+ occurrences = CountOccurrences(input, 'G', ref index);
+
+ // it doesn't matter how many 'G's, since .NET only supports 'g' or 'gg', and they
+ // have the same meaning
+ destination.Append('g');
+ break;
+ case 'y':
+ // a single 'y' in ICU is the year with no padding or trimming.
+ // a single 'y' in .NET is the year with 1 or 2 digits
+ // so convert any single 'y' to 'yyyy'
+ occurrences = CountOccurrences(input, 'y', ref index);
+ if (occurrences == 1)
+ {
+ occurrences = 4;
+ }
+ destination.Append('y', occurrences);
+ break;
+ default:
+ const string unsupportedDateFieldSymbols = "YuUrQqwWDFg";
+ Contract.Assert(unsupportedDateFieldSymbols.IndexOf(input[index]) == -1,
+ string.Format(CultureInfo.InvariantCulture,
+ "Encountered an unexpected date field symbol '{0}' from ICU which has no known corresponding .NET equivalent.",
+ input[index]));
+
+ destination.Append(input[index++]);
+ break;
+ }
+ }
+
+ return StringBuilderCache.GetStringAndRelease(destination);
+ }
+
+ private static void NormalizeDayOfWeek(string input, StringBuilder destination, ref int index)
+ {
+ char dayChar = input[index];
+ int occurrences = CountOccurrences(input, dayChar, ref index);
+ occurrences = Math.Max(occurrences, 3);
+ if (occurrences > 4)
+ {
+ // 5 and 6 E/e/c characters in ICU is the super short names, which maps closest to ddd in .NET
+ occurrences = 3;
+ }
+
+ destination.Append('d', occurrences);
+ }
+
+ private static int CountOccurrences(string input, char value, ref int index)
+ {
+ int startIndex = index;
+ while (index < input.Length && input[index] == value)
+ {
+ index++;
+ }
+
+ return index - startIndex;
+ }
+
+ [SecuritySafeCritical]
+ private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] monthNames)
+ {
+ monthNames = null;
+
+ CallbackContext callbackContext = new CallbackContext();
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext);
+ if (result)
+ {
+ // the month-name arrays are expected to have 13 elements. If ICU only returns 12, add an
+ // extra empty string to fill the array.
+ if (callbackContext.Results.Count == 12)
+ {
+ callbackContext.Results.Add(string.Empty);
+ }
+
+ monthNames = callbackContext.Results.ToArray();
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ private static bool EnumEraNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] eraNames)
+ {
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, out eraNames);
+
+ // .NET expects that only the Japanese calendars have more than 1 era.
+ // So for other calendars, only return the latest era.
+ if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames.Length > 0)
+ {
+ string[] latestEraName = new string[] { eraNames[eraNames.Length - 1] };
+ eraNames = latestEraName;
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] calendarData)
+ {
+ calendarData = null;
+
+ CallbackContext callbackContext = new CallbackContext();
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext);
+ if (result)
+ {
+ calendarData = callbackContext.Results.ToArray();
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ private static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, CallbackContext callbackContext)
+ {
+ GCHandle context = GCHandle.Alloc(callbackContext);
+ try
+ {
+ return Interop.GlobalizationInterop.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)context);
+ }
+ finally
+ {
+ context.Free();
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static void EnumCalendarInfoCallback(string calendarString, IntPtr context)
+ {
+ CallbackContext callbackContext = (CallbackContext)((GCHandle)context).Target;
+
+ if (callbackContext.DisallowDuplicates)
+ {
+ foreach (string existingResult in callbackContext.Results)
+ {
+ if (string.Equals(calendarString, existingResult, StringComparison.Ordinal))
+ {
+ // the value is already in the results, so don't add it again
+ return;
+ }
+ }
+ }
+
+ callbackContext.Results.Add(calendarString);
+ }
+
+ private class CallbackContext
+ {
+ private List<string> _results = new List<string>();
+
+ public CallbackContext()
+ {
+ }
+
+ public List<string> Results { get { return _results; } }
+
+ public bool DisallowDuplicates { get; set; }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs b/src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs
new file mode 100644
index 0000000000..bdf3ff1881
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs
@@ -0,0 +1,469 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+
+namespace System.Globalization
+{
+ internal partial class CalendarData
+ {
+ private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId)
+ {
+ bool ret = true;
+
+ uint useOverrides = this.bUseUserOverrides ? 0 : CAL_NOUSEROVERRIDE;
+
+ //
+ // Windows doesn't support some calendars right now, so remap those.
+ //
+ switch (calendarId)
+ {
+ case CalendarId.JAPANESELUNISOLAR: // Data looks like Japanese
+ calendarId = CalendarId.JAPAN;
+ break;
+ case CalendarId.JULIAN: // Data looks like gregorian US
+ case CalendarId.CHINESELUNISOLAR: // Algorithmic, so actual data is irrelevent
+ case CalendarId.SAKA: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.LUNAR_ETO_CHN: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.LUNAR_ETO_KOR: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.LUNAR_ETO_ROKUYOU: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.KOREANLUNISOLAR: // Algorithmic, so actual data is irrelevent
+ case CalendarId.TAIWANLUNISOLAR: // Algorithmic, so actual data is irrelevent
+ calendarId = CalendarId.GREGORIAN_US;
+ break;
+ }
+
+ //
+ // Special handling for some special calendar due to OS limitation.
+ // This includes calendar like Taiwan calendar, UmAlQura calendar, etc.
+ //
+ CheckSpecialCalendar(ref calendarId, ref localeName);
+
+ // Numbers
+ ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_ITWODIGITYEARMAX | useOverrides, out this.iTwoDigitYearMax);
+
+ // Strings
+ ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SCALNAME, out this.sNativeName);
+ ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SMONTHDAY | useOverrides, out this.sMonthDay);
+
+ // String Arrays
+ // Formats
+ ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SSHORTDATE, LOCALE_SSHORTDATE | useOverrides, out this.saShortDates);
+ ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SLONGDATE, LOCALE_SLONGDATE | useOverrides, out this.saLongDates);
+
+ // Get the YearMonth pattern.
+ ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SYEARMONTH, LOCALE_SYEARMONTH, out this.saYearMonths);
+
+ // Day & Month Names
+ // These are all single calType entries, 1 per day, so we have to make 7 or 13 calls to collect all the names
+
+ // Day
+ // Note that we're off-by-one since managed starts on sunday and windows starts on monday
+ ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SDAYNAME7, out this.saDayNames);
+ ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SABBREVDAYNAME7, out this.saAbbrevDayNames);
+
+ // Month names
+ ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1, out this.saMonthNames);
+ ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1, out this.saAbbrevMonthNames);
+
+ //
+ // The following LCTYPE are not supported in some platforms. If the call fails,
+ // don't return a failure.
+ //
+ GetCalendarDayInfo(localeName, calendarId, CAL_SSHORTESTDAYNAME7, out this.saSuperShortDayNames);
+
+ // Gregorian may have genitive month names
+ if (calendarId == CalendarId.GREGORIAN)
+ {
+ GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saMonthGenitiveNames);
+ GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saAbbrevMonthGenitiveNames);
+ }
+
+ // Calendar Parts Names
+ // This doesn't get always get localized names for gregorian (not available in windows < 7)
+ // so: eg: coreclr on win < 7 won't get these
+ CallEnumCalendarInfo(localeName, calendarId, CAL_SERASTRING, 0, out this.saEraNames);
+ CallEnumCalendarInfo(localeName, calendarId, CAL_SABBREVERASTRING, 0, out this.saAbbrevEraNames);
+
+ //
+ // Calendar Era Info
+ // Note that calendar era data (offsets, etc) is hard coded for each calendar since this
+ // data is implementation specific and not dynamic (except perhaps Japanese)
+ //
+
+ // Clean up the escaping of the formats
+ this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates);
+ this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates);
+ this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths);
+ this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay);
+
+ return ret;
+ }
+
+ // Get native two digit year max
+ internal static int GetTwoDigitYearMax(CalendarId calendarId)
+ {
+ int twoDigitYearMax = -1;
+
+ if (!CallGetCalendarInfoEx(null, calendarId, (uint)CAL_ITWODIGITYEARMAX, out twoDigitYearMax))
+ {
+ twoDigitYearMax = -1;
+ }
+
+ return twoDigitYearMax;
+ }
+
+ // Call native side to figure out which calendars are allowed
+ internal static int GetCalendars(String localeName, bool useUserOverride, CalendarId[] calendars)
+ {
+ EnumCalendarsData data = new EnumCalendarsData();
+ data.userOverride = 0;
+ data.calendars = new LowLevelList<int>();
+
+ // First call GetLocaleInfo if necessary
+ if (useUserOverride)
+ {
+ // They want user overrides, see if the user calendar matches the input calendar
+ int userCalendar = Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE);
+
+ // If we got a default, then use it as the first calendar
+ if (userCalendar != 0)
+ {
+ data.userOverride = userCalendar;
+ data.calendars.Add(userCalendar);
+ }
+ }
+
+ GCHandle contextHandle = GCHandle.Alloc(data);
+ try
+ {
+ // Now call the enumeration API. Work is done by our callback function
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, IntPtr, Interop.BOOL>>(EnumCalendarsCallback);
+ Interop.mincore.EnumCalendarInfoExEx(callback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle);
+ }
+ finally
+ {
+ contextHandle.Free();
+ }
+
+ // Copy to the output array
+ for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++)
+ calendars[i] = (CalendarId)data.calendars[i];
+
+ // Now we have a list of data, return the count
+ return data.calendars.Count;
+ }
+
+ private static bool SystemSupportsTaiwaneseCalendar()
+ {
+ string data;
+ // Taiwanese calendar get listed as one of the optional zh-TW calendars only when having zh-TW UI
+ return CallGetCalendarInfoEx("zh-TW", CalendarId.TAIWAN, CAL_SCALNAME, out data);
+ }
+
+ // PAL Layer ends here
+
+ private const uint CAL_RETURN_NUMBER = 0x20000000;
+ private const uint CAL_RETURN_GENITIVE_NAMES = 0x10000000;
+ private const uint CAL_NOUSEROVERRIDE = 0x80000000;
+ private const uint CAL_SCALNAME = 0x00000002;
+ private const uint CAL_SMONTHDAY = 0x00000038;
+ private const uint CAL_SSHORTDATE = 0x00000005;
+ private const uint CAL_SLONGDATE = 0x00000006;
+ private const uint CAL_SYEARMONTH = 0x0000002f;
+ private const uint CAL_SDAYNAME7 = 0x0000000d;
+ private const uint CAL_SABBREVDAYNAME7 = 0x00000014;
+ private const uint CAL_SMONTHNAME1 = 0x00000015;
+ private const uint CAL_SABBREVMONTHNAME1 = 0x00000022;
+ private const uint CAL_SSHORTESTDAYNAME7 = 0x00000037;
+ private const uint CAL_SERASTRING = 0x00000004;
+ private const uint CAL_SABBREVERASTRING = 0x00000039;
+ private const uint CAL_ICALINTVALUE = 0x00000001;
+ private const uint CAL_ITWODIGITYEARMAX = 0x00000030;
+
+ private const uint ENUM_ALL_CALENDARS = 0xffffffff;
+
+ private const uint LOCALE_SSHORTDATE = 0x0000001F;
+ private const uint LOCALE_SLONGDATE = 0x00000020;
+ private const uint LOCALE_SYEARMONTH = 0x00001006;
+ private const uint LOCALE_ICALENDARTYPE = 0x00001009;
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // For calendars like Gregorain US/Taiwan/UmAlQura, they are not available
+ // in all OS or all localized versions of OS.
+ // If OS does not support these calendars, we will fallback by using the
+ // appropriate fallback calendar and locale combination to retrieve data from OS.
+ //
+ // Parameters:
+ // __deref_inout pCalendarInt:
+ // Pointer to the calendar ID. This will be updated to new fallback calendar ID if needed.
+ // __in_out pLocaleNameStackBuffer
+ // Pointer to the StackSString object which holds the locale name to be checked.
+ // This will be updated to new fallback locale name if needed.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private static void CheckSpecialCalendar(ref CalendarId calendar, ref string localeName)
+ {
+ string data;
+
+ // Gregorian-US isn't always available in the OS, however it is the same for all locales
+ switch (calendar)
+ {
+ case CalendarId.GREGORIAN_US:
+ // See if this works
+ if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out data))
+ {
+ // Failed, set it to a locale (fa-IR) that's alway has Gregorian US available in the OS
+ localeName = "fa-IR";
+ }
+ // See if that works
+ if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out data))
+ {
+ // Failed again, just use en-US with the gregorian calendar
+ localeName = "en-US";
+ calendar = CalendarId.GREGORIAN;
+ }
+ break;
+ case CalendarId.TAIWAN:
+ // Taiwan calendar data is not always in all language version of OS due to Geopolical reasons.
+ // It is only available in zh-TW localized versions of Windows.
+ // Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar.
+ if (!SystemSupportsTaiwaneseCalendar())
+ {
+ calendar = CalendarId.GREGORIAN;
+ }
+ break;
+ }
+ }
+
+ private static bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out int data)
+ {
+ return (Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType | CAL_RETURN_NUMBER, IntPtr.Zero, 0, out data) != 0);
+ }
+
+ private static unsafe bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out string data)
+ {
+ const int BUFFER_LENGTH = 80;
+
+ // The maximum size for values returned from GetCalendarInfoEx is 80 characters.
+ char* buffer = stackalloc char[BUFFER_LENGTH];
+
+ int ret = Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType, (IntPtr)buffer, BUFFER_LENGTH, IntPtr.Zero);
+ if (ret > 0)
+ {
+ if (buffer[ret - 1] == '\0')
+ {
+ ret--; // don't include the null termination in the string
+ }
+ data = new string(buffer, 0, ret);
+ return true;
+ }
+ data = "";
+ return false;
+ }
+
+ // Context for EnumCalendarInfoExEx callback.
+ private class EnumData
+ {
+ public string userOverride;
+ public LowLevelList<string> strings;
+ }
+
+ // EnumCalendarInfoExEx callback itself.
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static unsafe Interop.BOOL EnumCalendarInfoCallback(IntPtr lpCalendarInfoString, uint calendar, IntPtr pReserved, IntPtr lParam)
+ {
+ EnumData context = (EnumData)((GCHandle)lParam).Target;
+ try
+ {
+ string calendarInfo = new string((char*)lpCalendarInfoString);
+
+ // If we had a user override, check to make sure this differs
+ if (context.userOverride != calendarInfo)
+ context.strings.Add(calendarInfo);
+
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[] data)
+ {
+ EnumData context = new EnumData();
+ context.userOverride = null;
+ context.strings = new LowLevelList<string>();
+
+ // First call GetLocaleInfo if necessary
+ if (((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0)) &&
+ // Get user locale, see if it matches localeName.
+ // Note that they should match exactly, including letter case
+ GetUserDefaultLocaleName() == localeName)
+ {
+ // They want user overrides, see if the user calendar matches the input calendar
+ CalendarId userCalendar = (CalendarId)Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE);
+
+ // If the calendars were the same, see if the locales were the same
+ if (userCalendar == calendar)
+ {
+ // They matched, get the user override since locale & calendar match
+ string res = Interop.mincore.GetLocaleInfoEx(localeName, lcType);
+
+ // if it succeeded remember the override for the later callers
+ if (res != "")
+ {
+ // Remember this was the override (so we can look for duplicates later in the enum function)
+ context.userOverride = res;
+
+ // Add to the result strings.
+ context.strings.Add(res);
+ }
+ }
+ }
+
+ GCHandle contextHandle = GCHandle.Alloc(context);
+ try
+ {
+ // Now call the enumeration API. Work is done by our callback function
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, IntPtr, Interop.BOOL>>(EnumCalendarInfoCallback);
+ Interop.mincore.EnumCalendarInfoExEx(callback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle);
+ }
+ finally
+ {
+ contextHandle.Free();
+ }
+
+ // Now we have a list of data, fail if we didn't find anything.
+ if (context.strings.Count == 0)
+ {
+ data = null;
+ return false;
+ }
+
+ string[] output = context.strings.ToArray();
+
+ if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING)
+ {
+ // Eras are enumerated backwards. (oldest era name first, but
+ // Japanese calendar has newest era first in array, and is only
+ // calendar with multiple eras)
+ Array.Reverse(output, 0, output.Length);
+ }
+
+ data = output;
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the native day names
+ //
+ // NOTE: There's a disparity between .Net & windows day orders, the input day should
+ // start with Sunday
+ //
+ // Parameters:
+ // OUT pOutputStrings The output string[] value.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private static bool GetCalendarDayInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings)
+ {
+ bool result = true;
+
+ //
+ // We'll need a new array of 7 items
+ //
+ string[] results = new string[7];
+
+ // Get each one of them
+ for (int i = 0; i < 7; i++, calType++)
+ {
+ result &= CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]);
+
+ // On the first iteration we need to go from CAL_SDAYNAME7 to CAL_SDAYNAME1, so subtract 7 before the ++ happens
+ // This is because the framework starts on sunday and windows starts on monday when counting days
+ if (i == 0)
+ calType -= 7;
+ }
+
+ outputStrings = results;
+
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the native month names
+ //
+ // Parameters:
+ // OUT pOutputStrings The output string[] value.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private static bool GetCalendarMonthInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings)
+ {
+ //
+ // We'll need a new array of 13 items
+ //
+ string[] results = new string[13];
+
+ // Get each one of them
+ for (int i = 0; i < 13; i++, calType++)
+ {
+ if (!CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]))
+ results[i] = "";
+ }
+
+ outputStrings = results;
+
+ return true;
+ }
+
+ //
+ // struct to help our calendar data enumaration callback
+ //
+ private class EnumCalendarsData
+ {
+ public int userOverride; // user override value (if found)
+ public LowLevelList<int> calendars; // list of calendars found so far
+ }
+
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static Interop.BOOL EnumCalendarsCallback(IntPtr lpCalendarInfoString, uint calendar, IntPtr reserved, IntPtr lParam)
+ {
+ EnumCalendarsData context = (EnumCalendarsData)((GCHandle)lParam).Target;
+ try
+ {
+ // If we had a user override, check to make sure this differs
+ if (context.userOverride != calendar)
+ context.calendars.Add((int)calendar);
+
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe String GetUserDefaultLocaleName()
+ {
+ const int LOCALE_NAME_MAX_LENGTH = 85;
+ const uint LOCALE_SNAME = 0x0000005c;
+ const string LOCALE_NAME_USER_DEFAULT = null;
+
+ int result;
+ char* localeName = stackalloc char[LOCALE_NAME_MAX_LENGTH];
+ result = Interop.mincore.GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, localeName, LOCALE_NAME_MAX_LENGTH);
+
+ return result <= 0 ? "" : new String(localeName, 0, result - 1); // exclude the null termination
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarData.cs b/src/mscorlib/corefx/System/Globalization/CalendarData.cs
new file mode 100644
index 0000000000..2dbd1b8069
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarData.cs
@@ -0,0 +1,381 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+
+namespace System.Globalization
+{
+ // List of calendar data
+ // Note the we cache overrides.
+ // Note that localized names (resource names) aren't available from here.
+ //
+ // NOTE: Calendars depend on the locale name that creates it. Only a few
+ // properties are available without locales using CalendarData.GetCalendar(CalendarData)
+
+ internal partial class CalendarData
+ {
+ // Max calendars
+ internal const int MAX_CALENDARS = 23;
+
+ // Identity
+ internal String sNativeName; // Calendar Name for the locale
+
+ // Formats
+ internal String[] saShortDates; // Short Data format, default first
+ internal String[] saYearMonths; // Year/Month Data format, default first
+ internal String[] saLongDates; // Long Data format, default first
+ internal String sMonthDay; // Month/Day format
+
+ // Calendar Parts Names
+ internal String[] saEraNames; // Names of Eras
+ internal String[] saAbbrevEraNames; // Abbreviated Era Names
+ internal String[] saAbbrevEnglishEraNames; // Abbreviated Era Names in English
+ internal String[] saDayNames; // Day Names, null to use locale data, starts on Sunday
+ internal String[] saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday
+ internal String[] saSuperShortDayNames; // Super short Day of week names
+ internal String[] saMonthNames; // Month Names (13)
+ internal String[] saAbbrevMonthNames; // Abbrev Month Names (13)
+ internal String[] saMonthGenitiveNames; // Genitive Month Names (13)
+ internal String[] saAbbrevMonthGenitiveNames; // Genitive Abbrev Month Names (13)
+ internal String[] saLeapYearMonthNames; // Multiple strings for the month names in a leap year.
+
+ // Integers at end to make marshaller happier
+ internal int iTwoDigitYearMax = 2029; // Max 2 digit year (for Y2K bug data entry)
+ internal int iCurrentEra = 0; // current era # (usually 1)
+
+ // Use overrides?
+ internal bool bUseUserOverrides; // True if we want user overrides.
+
+ // Static invariant for the invariant locale
+ internal static CalendarData Invariant;
+
+ // Private constructor
+ private CalendarData() { }
+
+ // Invariant constructor
+ static CalendarData()
+ {
+ // Set our default/gregorian US calendar data
+ // Calendar IDs are 1-based, arrays are 0 based.
+ CalendarData invariant = new CalendarData();
+
+ // Set default data for calendar
+ // Note that we don't load resources since this IS NOT supposed to change (by definition)
+ invariant.sNativeName = "Gregorian Calendar"; // Calendar Name
+
+ // Year
+ invariant.iTwoDigitYearMax = 2029; // Max 2 digit year (for Y2K bug data entry)
+ invariant.iCurrentEra = 1; // Current era #
+
+ // Formats
+ invariant.saShortDates = new String[] { "MM/dd/yyyy", "yyyy-MM-dd" }; // short date format
+ invariant.saLongDates = new String[] { "dddd, dd MMMM yyyy" }; // long date format
+ invariant.saYearMonths = new String[] { "yyyy MMMM" }; // year month format
+ invariant.sMonthDay = "MMMM dd"; // Month day pattern
+
+ // Calendar Parts Names
+ invariant.saEraNames = new String[] { "A.D." }; // Era names
+ invariant.saAbbrevEraNames = new String[] { "AD" }; // Abbreviated Era names
+ invariant.saAbbrevEnglishEraNames = new String[] { "AD" }; // Abbreviated era names in English
+ invariant.saDayNames = new String[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };// day names
+ invariant.saAbbrevDayNames = new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; // abbreviated day names
+ invariant.saSuperShortDayNames = new String[] { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" }; // The super short day names
+ invariant.saMonthNames = new String[] { "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December", String.Empty}; // month names
+ invariant.saAbbrevMonthNames = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", String.Empty}; // abbreviated month names
+ invariant.saMonthGenitiveNames = invariant.saMonthNames; // Genitive month names (same as month names for invariant)
+ invariant.saAbbrevMonthGenitiveNames = invariant.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant)
+ invariant.saLeapYearMonthNames = invariant.saMonthNames; // leap year month names are unused in Gregorian English (invariant)
+
+ invariant.bUseUserOverrides = false;
+
+ // Calendar was built, go ahead and assign it...
+ Invariant = invariant;
+ }
+
+ //
+ // Get a bunch of data for a calendar
+ //
+ internal CalendarData(String localeName, CalendarId calendarId, bool bUseUserOverrides)
+ {
+ this.bUseUserOverrides = bUseUserOverrides;
+
+ if (!LoadCalendarDataFromSystem(localeName, calendarId))
+ {
+ Contract.Assert(false, "[CalendarData] LoadCalendarDataFromSystem call isn't expected to fail for calendar " + calendarId + " locale " + localeName);
+
+ // Something failed, try invariant for missing parts
+ // This is really not good, but we don't want the callers to crash.
+ if (this.sNativeName == null) this.sNativeName = String.Empty; // Calendar Name for the locale.
+
+ // Formats
+ if (this.saShortDates == null) this.saShortDates = Invariant.saShortDates; // Short Data format, default first
+ if (this.saYearMonths == null) this.saYearMonths = Invariant.saYearMonths; // Year/Month Data format, default first
+ if (this.saLongDates == null) this.saLongDates = Invariant.saLongDates; // Long Data format, default first
+ if (this.sMonthDay == null) this.sMonthDay = Invariant.sMonthDay; // Month/Day format
+
+ // Calendar Parts Names
+ if (this.saEraNames == null) this.saEraNames = Invariant.saEraNames; // Names of Eras
+ if (this.saAbbrevEraNames == null) this.saAbbrevEraNames = Invariant.saAbbrevEraNames; // Abbreviated Era Names
+ if (this.saAbbrevEnglishEraNames == null) this.saAbbrevEnglishEraNames = Invariant.saAbbrevEnglishEraNames; // Abbreviated Era Names in English
+ if (this.saDayNames == null) this.saDayNames = Invariant.saDayNames; // Day Names, null to use locale data, starts on Sunday
+ if (this.saAbbrevDayNames == null) this.saAbbrevDayNames = Invariant.saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday
+ if (this.saSuperShortDayNames == null) this.saSuperShortDayNames = Invariant.saSuperShortDayNames; // Super short Day of week names
+ if (this.saMonthNames == null) this.saMonthNames = Invariant.saMonthNames; // Month Names (13)
+ if (this.saAbbrevMonthNames == null) this.saAbbrevMonthNames = Invariant.saAbbrevMonthNames; // Abbrev Month Names (13)
+ // Genitive and Leap names can follow the fallback below
+ }
+
+ if (calendarId == CalendarId.TAIWAN)
+ {
+ if (SystemSupportsTaiwaneseCalendar())
+ {
+ // We got the month/day names from the OS (same as gregorian), but the native name is wrong
+ this.sNativeName = "\x4e2d\x83ef\x6c11\x570b\x66c6";
+ }
+ else
+ {
+ this.sNativeName = String.Empty;
+ }
+ }
+
+ // Check for null genitive names (in case unmanaged side skips it for non-gregorian calendars, etc)
+ if (this.saMonthGenitiveNames == null || this.saMonthGenitiveNames.Length == 0 || String.IsNullOrEmpty(this.saMonthGenitiveNames[0]))
+ this.saMonthGenitiveNames = this.saMonthNames; // Genitive month names (same as month names for invariant)
+ if (this.saAbbrevMonthGenitiveNames == null || this.saAbbrevMonthGenitiveNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevMonthGenitiveNames[0]))
+ this.saAbbrevMonthGenitiveNames = this.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant)
+ if (this.saLeapYearMonthNames == null || this.saLeapYearMonthNames.Length == 0 || String.IsNullOrEmpty(this.saLeapYearMonthNames[0]))
+ this.saLeapYearMonthNames = this.saMonthNames;
+
+ InitializeEraNames(localeName, calendarId);
+
+ InitializeAbbreviatedEraNames(localeName, calendarId);
+
+ // Abbreviated English Era Names are only used for the Japanese calendar.
+ if (calendarId == CalendarId.JAPAN)
+ {
+ this.saAbbrevEnglishEraNames = JapaneseCalendar.EnglishEraNames();
+ }
+ else
+ {
+ // For all others just use the an empty string (doesn't matter we'll never ask for it for other calendars)
+ this.saAbbrevEnglishEraNames = new String[] { "" };
+ }
+
+ // Japanese is the only thing with > 1 era. Its current era # is how many ever
+ // eras are in the array. (And the others all have 1 string in the array)
+ this.iCurrentEra = this.saEraNames.Length;
+ }
+
+ private void InitializeEraNames(string localeName, CalendarId calendarId)
+ {
+ // Note that the saEraNames only include "A.D." We don't have localized names for other calendars available from windows
+ switch (calendarId)
+ {
+ // For Localized Gregorian we really expect the data from the OS.
+ case CalendarId.GREGORIAN:
+ // Fallback for CoreCLR < Win7 or culture.dll missing
+ if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
+ {
+ this.saEraNames = new String[] { "A.D." };
+ }
+ break;
+
+ // The rest of the calendars have constant data, so we'll just use that
+ case CalendarId.GREGORIAN_US:
+ case CalendarId.JULIAN:
+ this.saEraNames = new String[] { "A.D." };
+ break;
+ case CalendarId.HEBREW:
+ this.saEraNames = new String[] { "C.E." };
+ break;
+ case CalendarId.HIJRI:
+ case CalendarId.UMALQURA:
+ if (localeName == "dv-MV")
+ {
+ // Special case for Divehi
+ this.saEraNames = new String[] { "\x0780\x07a8\x0796\x07b0\x0783\x07a9" };
+ }
+ else
+ {
+ this.saEraNames = new String[] { "\x0628\x0639\x062F \x0627\x0644\x0647\x062C\x0631\x0629" };
+ }
+ break;
+ case CalendarId.GREGORIAN_ARABIC:
+ case CalendarId.GREGORIAN_XLIT_ENGLISH:
+ case CalendarId.GREGORIAN_XLIT_FRENCH:
+ // These are all the same:
+ this.saEraNames = new String[] { "\x0645" };
+ break;
+
+ case CalendarId.GREGORIAN_ME_FRENCH:
+ this.saEraNames = new String[] { "ap. J.-C." };
+ break;
+
+ case CalendarId.TAIWAN:
+ if (SystemSupportsTaiwaneseCalendar())
+ {
+ this.saEraNames = new String[] { "\x4e2d\x83ef\x6c11\x570b" };
+ }
+ else
+ {
+ this.saEraNames = new String[] { String.Empty };
+ }
+ break;
+
+ case CalendarId.KOREA:
+ this.saEraNames = new String[] { "\xb2e8\xae30" };
+ break;
+
+ case CalendarId.THAI:
+ this.saEraNames = new String[] { "\x0e1e\x002e\x0e28\x002e" };
+ break;
+
+ case CalendarId.JAPAN:
+ case CalendarId.JAPANESELUNISOLAR:
+ this.saEraNames = JapaneseCalendar.EraNames();
+ break;
+
+ case CalendarId.PERSIAN:
+ if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
+ {
+ this.saEraNames = new String[] { "\x0647\x002e\x0634" };
+ }
+ break;
+
+ default:
+ // Most calendars are just "A.D."
+ this.saEraNames = Invariant.saEraNames;
+ break;
+ }
+ }
+
+ private void InitializeAbbreviatedEraNames(string localeName, CalendarId calendarId)
+ {
+ // Note that the saAbbrevEraNames only include "AD" We don't have localized names for other calendars available from windows
+ switch (calendarId)
+ {
+ // For Localized Gregorian we really expect the data from the OS.
+ case CalendarId.GREGORIAN:
+ // Fallback for CoreCLR < Win7 or culture.dll missing
+ if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
+ {
+ this.saAbbrevEraNames = new String[] { "AD" };
+ }
+ break;
+
+ // The rest of the calendars have constant data, so we'll just use that
+ case CalendarId.GREGORIAN_US:
+ case CalendarId.JULIAN:
+ this.saAbbrevEraNames = new String[] { "AD" };
+ break;
+ case CalendarId.JAPAN:
+ case CalendarId.JAPANESELUNISOLAR:
+ this.saAbbrevEraNames = JapaneseCalendar.AbbrevEraNames();
+ break;
+ case CalendarId.HIJRI:
+ case CalendarId.UMALQURA:
+ if (localeName == "dv-MV")
+ {
+ // Special case for Divehi
+ this.saAbbrevEraNames = new String[] { "\x0780\x002e" };
+ }
+ else
+ {
+ this.saAbbrevEraNames = new String[] { "\x0647\x0640" };
+ }
+ break;
+ case CalendarId.TAIWAN:
+ // Get era name and abbreviate it
+ this.saAbbrevEraNames = new String[1];
+ if (this.saEraNames[0].Length == 4)
+ {
+ this.saAbbrevEraNames[0] = this.saEraNames[0].Substring(2, 2);
+ }
+ else
+ {
+ this.saAbbrevEraNames[0] = this.saEraNames[0];
+ }
+ break;
+
+ case CalendarId.PERSIAN:
+ if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
+ {
+ this.saAbbrevEraNames = this.saEraNames;
+ }
+ break;
+
+ default:
+ // Most calendars just use the full name
+ this.saAbbrevEraNames = this.saEraNames;
+ break;
+ }
+ }
+
+ internal static CalendarData GetCalendarData(CalendarId calendarId)
+ {
+ //
+ // Get a calendar.
+ // Unfortunately we depend on the locale in the OS, so we need a locale
+ // no matter what. So just get the appropriate calendar from the
+ // appropriate locale here
+ //
+
+ // Get a culture name
+ // TODO: Note that this doesn't handle the new calendars (lunisolar, etc)
+ String culture = CalendarIdToCultureName(calendarId);
+
+ // Return our calendar
+ return CultureInfo.GetCultureInfo(culture).m_cultureData.GetCalendar(calendarId);
+ }
+
+ private static String CalendarIdToCultureName(CalendarId calendarId)
+ {
+ switch (calendarId)
+ {
+ case CalendarId.GREGORIAN_US:
+ return "fa-IR"; // "fa-IR" Iran
+
+ case CalendarId.JAPAN:
+ return "ja-JP"; // "ja-JP" Japan
+
+ case CalendarId.TAIWAN:
+ return "zh-TW"; // zh-TW Taiwan
+
+ case CalendarId.KOREA:
+ return "ko-KR"; // "ko-KR" Korea
+
+ case CalendarId.HIJRI:
+ case CalendarId.GREGORIAN_ARABIC:
+ case CalendarId.UMALQURA:
+ return "ar-SA"; // "ar-SA" Saudi Arabia
+
+ case CalendarId.THAI:
+ return "th-TH"; // "th-TH" Thailand
+
+ case CalendarId.HEBREW:
+ return "he-IL"; // "he-IL" Israel
+
+ case CalendarId.GREGORIAN_ME_FRENCH:
+ return "ar-DZ"; // "ar-DZ" Algeria
+
+ case CalendarId.GREGORIAN_XLIT_ENGLISH:
+ case CalendarId.GREGORIAN_XLIT_FRENCH:
+ return "ar-IQ"; // "ar-IQ"; Iraq
+
+ default:
+ // Default to gregorian en-US
+ break;
+ }
+
+ return "en-US";
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs b/src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs
new file mode 100644
index 0000000000..490951e1f0
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public enum CalendarWeekRule
+ {
+ FirstDay = 0, // Week 1 begins on the first day of the year
+
+ FirstFullWeek = 1, // Week 1 begins on first FirstDayOfWeek not before the first day of the year
+
+ FirstFourDayWeek = 2 // Week 1 begins on first FirstDayOfWeek such that FirstDayOfWeek+3 is not before the first day of the year
+ };
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs b/src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs
new file mode 100644
index 0000000000..ba7601b420
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs
@@ -0,0 +1,413 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ internal class CalendricalCalculationsHelper
+ {
+ private const double FullCircleOfArc = 360.0; // 360.0;
+ private const int HalfCircleOfArc = 180;
+ private const double TwelveHours = 0.5; // half a day
+ private const double Noon2000Jan01 = 730120.5;
+ internal const double MeanTropicalYearInDays = 365.242189;
+ private const double MeanSpeedOfSun = MeanTropicalYearInDays / FullCircleOfArc;
+ private const double LongitudeSpring = 0.0;
+ private const double TwoDegreesAfterSpring = 2.0;
+ private const int SecondsPerDay = 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds
+
+ private const int DaysInUniformLengthCentury = 36525;
+ private const int SecondsPerMinute = 60;
+ private const int MinutesPerDegree = 60;
+
+ private static readonly long StartOf1810 = GetNumberOfDays(new DateTime(1810, 1, 1));
+ private static readonly long StartOf1900Century = GetNumberOfDays(new DateTime(1900, 1, 1));
+
+ private static readonly double[] s_coefficients1900to1987 = new double[] { -0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591 };
+ private static readonly double[] s_coefficients1800to1899 = new double[] { -0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794 };
+ private static readonly double[] s_coefficients1700to1799 = new double[] { 8.118780842, -0.005092142, 0.003336121, -0.0000266484 };
+ private static readonly double[] s_coefficients1620to1699 = new double[] { 196.58333, -4.0675, 0.0219167 };
+ private static readonly double[] s_lambdaCoefficients = new double[] { 280.46645, 36000.76983, 0.0003032 };
+ private static readonly double[] s_anomalyCoefficients = new double[] { 357.52910, 35999.05030, -0.0001559, -0.00000048 };
+ private static readonly double[] s_eccentricityCoefficients = new double[] { 0.016708617, -0.000042037, -0.0000001236 };
+ private static readonly double[] s_coefficients = new double[] { Angle(23, 26, 21.448), Angle(0, 0, -46.8150), Angle(0, 0, -0.00059), Angle(0, 0, 0.001813) };
+ private static readonly double[] s_coefficientsA = new double[] { 124.90, -1934.134, 0.002063 };
+ private static readonly double[] s_coefficientsB = new double[] { 201.11, 72001.5377, 0.00057 };
+
+ private static double RadiansFromDegrees(double degree)
+ {
+ return degree * Math.PI / 180;
+ }
+
+ private static double SinOfDegree(double degree)
+ {
+ return Math.Sin(RadiansFromDegrees(degree));
+ }
+
+ private static double CosOfDegree(double degree)
+ {
+ return Math.Cos(RadiansFromDegrees(degree));
+ }
+ private static double TanOfDegree(double degree)
+ {
+ return Math.Tan(RadiansFromDegrees(degree));
+ }
+
+ public static double Angle(int degrees, int minutes, double seconds)
+ {
+ return ((seconds / SecondsPerMinute + minutes) / MinutesPerDegree) + degrees;
+ }
+
+ private static double Obliquity(double julianCenturies)
+ {
+ return PolynomialSum(s_coefficients, julianCenturies);
+ }
+
+ internal static long GetNumberOfDays(DateTime date)
+ {
+ return date.Ticks / GregorianCalendar.TicksPerDay;
+ }
+
+ private static int GetGregorianYear(double numberOfDays)
+ {
+ return new DateTime(Math.Min((long)(Math.Floor(numberOfDays) * GregorianCalendar.TicksPerDay), DateTime.MaxValue.Ticks)).Year;
+ }
+
+ private enum CorrectionAlgorithm
+ {
+ Default,
+ Year1988to2019,
+ Year1900to1987,
+ Year1800to1899,
+ Year1700to1799,
+ Year1620to1699
+ }
+
+ private struct EphemerisCorrectionAlgorithmMap
+ {
+ public EphemerisCorrectionAlgorithmMap(int year, CorrectionAlgorithm algorithm)
+ {
+ _lowestYear = year;
+ _algorithm = algorithm;
+ }
+
+ internal int _lowestYear;
+ internal CorrectionAlgorithm _algorithm;
+ };
+
+ private static readonly EphemerisCorrectionAlgorithmMap[] s_ephemerisCorrectionTable = new EphemerisCorrectionAlgorithmMap[]
+ {
+ // lowest year that starts algorithm, algorithm to use
+ new EphemerisCorrectionAlgorithmMap(2020, CorrectionAlgorithm.Default),
+ new EphemerisCorrectionAlgorithmMap(1988, CorrectionAlgorithm.Year1988to2019),
+ new EphemerisCorrectionAlgorithmMap(1900, CorrectionAlgorithm.Year1900to1987),
+ new EphemerisCorrectionAlgorithmMap(1800, CorrectionAlgorithm.Year1800to1899),
+ new EphemerisCorrectionAlgorithmMap(1700, CorrectionAlgorithm.Year1700to1799),
+ new EphemerisCorrectionAlgorithmMap(1620, CorrectionAlgorithm.Year1620to1699),
+ new EphemerisCorrectionAlgorithmMap(int.MinValue, CorrectionAlgorithm.Default) // default must be last
+ };
+
+ private static double Reminder(double divisor, double dividend)
+ {
+ double whole = Math.Floor(divisor / dividend);
+ return divisor - (dividend * whole);
+ }
+
+ private static double NormalizeLongitude(double longitude)
+ {
+ longitude = Reminder(longitude, FullCircleOfArc);
+ if (longitude < 0)
+ {
+ longitude += FullCircleOfArc;
+ }
+ return longitude;
+ }
+
+ static public double AsDayFraction(double longitude)
+ {
+ return longitude / FullCircleOfArc;
+ }
+
+ private static double PolynomialSum(double[] coefficients, double indeterminate)
+ {
+ double sum = coefficients[0];
+ double indeterminateRaised = 1;
+ for (int i = 1; i < coefficients.Length; i++)
+ {
+ indeterminateRaised *= indeterminate;
+ sum += (coefficients[i] * indeterminateRaised);
+ }
+
+ return sum;
+ }
+
+ private static double CenturiesFrom1900(int gregorianYear)
+ {
+ long july1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 7, 1));
+ return (double)(july1stOfYear - StartOf1900Century) / DaysInUniformLengthCentury;
+ }
+
+ // the following formulas defines a polynomial function which gives us the amount that the earth is slowing down for specific year ranges
+ private static double DefaultEphemerisCorrection(int gregorianYear)
+ {
+ Contract.Assert(gregorianYear < 1620 || 2020 <= gregorianYear);
+ long january1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 1, 1));
+ double daysSinceStartOf1810 = january1stOfYear - StartOf1810;
+ double x = TwelveHours + daysSinceStartOf1810;
+ return ((Math.Pow(x, 2) / 41048480) - 15) / SecondsPerDay;
+ }
+
+ private static double EphemerisCorrection1988to2019(int gregorianYear)
+ {
+ Contract.Assert(1988 <= gregorianYear && gregorianYear <= 2019);
+ return (double)(gregorianYear - 1933) / SecondsPerDay;
+ }
+
+ private static double EphemerisCorrection1900to1987(int gregorianYear)
+ {
+ Contract.Assert(1900 <= gregorianYear && gregorianYear <= 1987);
+ double centuriesFrom1900 = CenturiesFrom1900(gregorianYear);
+ return PolynomialSum(s_coefficients1900to1987, centuriesFrom1900);
+ }
+
+ private static double EphemerisCorrection1800to1899(int gregorianYear)
+ {
+ Contract.Assert(1800 <= gregorianYear && gregorianYear <= 1899);
+ double centuriesFrom1900 = CenturiesFrom1900(gregorianYear);
+ return PolynomialSum(s_coefficients1800to1899, centuriesFrom1900);
+ }
+
+ private static double EphemerisCorrection1700to1799(int gregorianYear)
+ {
+ Contract.Assert(1700 <= gregorianYear && gregorianYear <= 1799);
+ double yearsSince1700 = gregorianYear - 1700;
+ return PolynomialSum(s_coefficients1700to1799, yearsSince1700) / SecondsPerDay;
+ }
+
+ private static double EphemerisCorrection1620to1699(int gregorianYear)
+ {
+ Contract.Assert(1620 <= gregorianYear && gregorianYear <= 1699);
+ double yearsSince1600 = gregorianYear - 1600;
+ return PolynomialSum(s_coefficients1620to1699, yearsSince1600) / SecondsPerDay;
+ }
+
+ // ephemeris-correction: correction to account for the slowing down of the rotation of the earth
+ private static double EphemerisCorrection(double time)
+ {
+ int year = GetGregorianYear(time);
+ foreach (EphemerisCorrectionAlgorithmMap map in s_ephemerisCorrectionTable)
+ {
+ if (map._lowestYear <= year)
+ {
+ switch (map._algorithm)
+ {
+ case CorrectionAlgorithm.Default: return DefaultEphemerisCorrection(year);
+ case CorrectionAlgorithm.Year1988to2019: return EphemerisCorrection1988to2019(year);
+ case CorrectionAlgorithm.Year1900to1987: return EphemerisCorrection1900to1987(year);
+ case CorrectionAlgorithm.Year1800to1899: return EphemerisCorrection1800to1899(year);
+ case CorrectionAlgorithm.Year1700to1799: return EphemerisCorrection1700to1799(year);
+ case CorrectionAlgorithm.Year1620to1699: return EphemerisCorrection1620to1699(year);
+ }
+
+ break; // break the loop and assert eventually
+ }
+ }
+
+ Contract.Assert(false, "Not expected to come here");
+ return DefaultEphemerisCorrection(year);
+ }
+
+ static public double JulianCenturies(double moment)
+ {
+ double dynamicalMoment = moment + EphemerisCorrection(moment);
+ return (dynamicalMoment - Noon2000Jan01) / DaysInUniformLengthCentury;
+ }
+
+ private static bool IsNegative(double value)
+ {
+ return Math.Sign(value) == -1;
+ }
+
+ private static double CopySign(double value, double sign)
+ {
+ return (IsNegative(value) == IsNegative(sign)) ? value : -value;
+ }
+
+ // equation-of-time; approximate the difference between apparent solar time and mean solar time
+ // formal definition is EOT = GHA - GMHA
+ // GHA is the Greenwich Hour Angle of the apparent (actual) Sun
+ // GMHA is the Greenwich Mean Hour Angle of the mean (fictitious) Sun
+ // http://www.esrl.noaa.gov/gmd/grad/solcalc/
+ // http://en.wikipedia.org/wiki/Equation_of_time
+ private static double EquationOfTime(double time)
+ {
+ double julianCenturies = JulianCenturies(time);
+ double lambda = PolynomialSum(s_lambdaCoefficients, julianCenturies);
+ double anomaly = PolynomialSum(s_anomalyCoefficients, julianCenturies);
+ double eccentricity = PolynomialSum(s_eccentricityCoefficients, julianCenturies);
+
+ double epsilon = Obliquity(julianCenturies);
+ double tanHalfEpsilon = TanOfDegree(epsilon / 2);
+ double y = tanHalfEpsilon * tanHalfEpsilon;
+
+ double dividend = ((y * SinOfDegree(2 * lambda))
+ - (2 * eccentricity * SinOfDegree(anomaly))
+ + (4 * eccentricity * y * SinOfDegree(anomaly) * CosOfDegree(2 * lambda))
+ - (0.5 * Math.Pow(y, 2) * SinOfDegree(4 * lambda))
+ - (1.25 * Math.Pow(eccentricity, 2) * SinOfDegree(2 * anomaly)));
+ double divisor = 2 * Math.PI;
+ double equation = dividend / divisor;
+
+ // approximation of equation of time is not valid for dates that are many millennia in the past or future
+ // thus limited to a half day
+ return CopySign(Math.Min(Math.Abs(equation), TwelveHours), equation);
+ }
+
+ private static double AsLocalTime(double apparentMidday, double longitude)
+ {
+ // slightly inaccurate since equation of time takes mean time not apparent time as its argument, but the difference is negligible
+ double universalTime = apparentMidday - AsDayFraction(longitude);
+ return apparentMidday - EquationOfTime(universalTime);
+ }
+
+ // midday
+ static public double Midday(double date, double longitude)
+ {
+ return AsLocalTime(date + TwelveHours, longitude) - AsDayFraction(longitude);
+ }
+
+ private static double InitLongitude(double longitude)
+ {
+ return NormalizeLongitude(longitude + HalfCircleOfArc) - HalfCircleOfArc;
+ }
+
+ // midday-in-tehran
+ static public double MiddayAtPersianObservationSite(double date)
+ {
+ return Midday(date, InitLongitude(52.5)); // 52.5 degrees east - longitude of UTC+3:30 which defines Iranian Standard Time
+ }
+
+ private static double PeriodicTerm(double julianCenturies, int x, double y, double z)
+ {
+ return x * SinOfDegree(y + z * julianCenturies);
+ }
+
+ private static double SumLongSequenceOfPeriodicTerms(double julianCenturies)
+ {
+ double sum = 0.0;
+ sum += PeriodicTerm(julianCenturies, 403406, 270.54861, 0.9287892);
+ sum += PeriodicTerm(julianCenturies, 195207, 340.19128, 35999.1376958);
+ sum += PeriodicTerm(julianCenturies, 119433, 63.91854, 35999.4089666);
+ sum += PeriodicTerm(julianCenturies, 112392, 331.2622, 35998.7287385);
+ sum += PeriodicTerm(julianCenturies, 3891, 317.843, 71998.20261);
+ sum += PeriodicTerm(julianCenturies, 2819, 86.631, 71998.4403);
+ sum += PeriodicTerm(julianCenturies, 1721, 240.052, 36000.35726);
+ sum += PeriodicTerm(julianCenturies, 660, 310.26, 71997.4812);
+ sum += PeriodicTerm(julianCenturies, 350, 247.23, 32964.4678);
+ sum += PeriodicTerm(julianCenturies, 334, 260.87, -19.441);
+ sum += PeriodicTerm(julianCenturies, 314, 297.82, 445267.1117);
+ sum += PeriodicTerm(julianCenturies, 268, 343.14, 45036.884);
+ sum += PeriodicTerm(julianCenturies, 242, 166.79, 3.1008);
+ sum += PeriodicTerm(julianCenturies, 234, 81.53, 22518.4434);
+ sum += PeriodicTerm(julianCenturies, 158, 3.5, -19.9739);
+ sum += PeriodicTerm(julianCenturies, 132, 132.75, 65928.9345);
+ sum += PeriodicTerm(julianCenturies, 129, 182.95, 9038.0293);
+ sum += PeriodicTerm(julianCenturies, 114, 162.03, 3034.7684);
+ sum += PeriodicTerm(julianCenturies, 99, 29.8, 33718.148);
+ sum += PeriodicTerm(julianCenturies, 93, 266.4, 3034.448);
+ sum += PeriodicTerm(julianCenturies, 86, 249.2, -2280.773);
+ sum += PeriodicTerm(julianCenturies, 78, 157.6, 29929.992);
+ sum += PeriodicTerm(julianCenturies, 72, 257.8, 31556.493);
+ sum += PeriodicTerm(julianCenturies, 68, 185.1, 149.588);
+ sum += PeriodicTerm(julianCenturies, 64, 69.9, 9037.75);
+ sum += PeriodicTerm(julianCenturies, 46, 8.0, 107997.405);
+ sum += PeriodicTerm(julianCenturies, 38, 197.1, -4444.176);
+ sum += PeriodicTerm(julianCenturies, 37, 250.4, 151.771);
+ sum += PeriodicTerm(julianCenturies, 32, 65.3, 67555.316);
+ sum += PeriodicTerm(julianCenturies, 29, 162.7, 31556.08);
+ sum += PeriodicTerm(julianCenturies, 28, 341.5, -4561.54);
+ sum += PeriodicTerm(julianCenturies, 27, 291.6, 107996.706);
+ sum += PeriodicTerm(julianCenturies, 27, 98.5, 1221.655);
+ sum += PeriodicTerm(julianCenturies, 25, 146.7, 62894.167);
+ sum += PeriodicTerm(julianCenturies, 24, 110.0, 31437.369);
+ sum += PeriodicTerm(julianCenturies, 21, 5.2, 14578.298);
+ sum += PeriodicTerm(julianCenturies, 21, 342.6, -31931.757);
+ sum += PeriodicTerm(julianCenturies, 20, 230.9, 34777.243);
+ sum += PeriodicTerm(julianCenturies, 18, 256.1, 1221.999);
+ sum += PeriodicTerm(julianCenturies, 17, 45.3, 62894.511);
+ sum += PeriodicTerm(julianCenturies, 14, 242.9, -4442.039);
+ sum += PeriodicTerm(julianCenturies, 13, 115.2, 107997.909);
+ sum += PeriodicTerm(julianCenturies, 13, 151.8, 119.066);
+ sum += PeriodicTerm(julianCenturies, 13, 285.3, 16859.071);
+ sum += PeriodicTerm(julianCenturies, 12, 53.3, -4.578);
+ sum += PeriodicTerm(julianCenturies, 10, 126.6, 26895.292);
+ sum += PeriodicTerm(julianCenturies, 10, 205.7, -39.127);
+ sum += PeriodicTerm(julianCenturies, 10, 85.9, 12297.536);
+ sum += PeriodicTerm(julianCenturies, 10, 146.1, 90073.778);
+ return sum;
+ }
+
+ private static double Aberration(double julianCenturies)
+ {
+ return (0.0000974 * CosOfDegree(177.63 + (35999.01848 * julianCenturies))) - 0.005575;
+ }
+
+ private static double Nutation(double julianCenturies)
+ {
+ double a = PolynomialSum(s_coefficientsA, julianCenturies);
+ double b = PolynomialSum(s_coefficientsB, julianCenturies);
+ return (-0.004778 * SinOfDegree(a)) - (0.0003667 * SinOfDegree(b));
+ }
+
+ static public double Compute(double time)
+ {
+ double julianCenturies = JulianCenturies(time);
+ double lambda = 282.7771834
+ + (36000.76953744 * julianCenturies)
+ + (0.000005729577951308232 * SumLongSequenceOfPeriodicTerms(julianCenturies));
+
+ double longitude = lambda + Aberration(julianCenturies) + Nutation(julianCenturies);
+ return InitLongitude(longitude);
+ }
+
+ static public double AsSeason(double longitude)
+ {
+ return (longitude < 0) ? (longitude + FullCircleOfArc) : longitude;
+ }
+
+ private static double EstimatePrior(double longitude, double time)
+ {
+ double timeSunLastAtLongitude = time - (MeanSpeedOfSun * AsSeason(InitLongitude(Compute(time) - longitude)));
+ double longitudeErrorDelta = InitLongitude(Compute(timeSunLastAtLongitude) - longitude);
+ return Math.Min(time, timeSunLastAtLongitude - (MeanSpeedOfSun * longitudeErrorDelta));
+ }
+
+ // persian-new-year-on-or-before
+ // number of days is the absolute date. The absolute date is the number of days from January 1st, 1 A.D.
+ // 1/1/0001 is absolute date 1.
+ internal static long PersianNewYearOnOrBefore(long numberOfDays)
+ {
+ double date = (double)numberOfDays;
+
+ double approx = EstimatePrior(LongitudeSpring, MiddayAtPersianObservationSite(date));
+ long lowerBoundNewYearDay = (long)Math.Floor(approx) - 1;
+ long upperBoundNewYearDay = lowerBoundNewYearDay + 3; // estimate is generally within a day of the actual occurrance (at the limits, the error expands, since the calculations rely on the mean tropical year which changes...)
+ long day = lowerBoundNewYearDay;
+ for (; day != upperBoundNewYearDay; ++day)
+ {
+ double midday = MiddayAtPersianObservationSite((double)day);
+ double l = Compute(midday);
+ if ((LongitudeSpring <= l) && (l <= TwoDegreesAfterSpring))
+ {
+ break;
+ }
+ }
+ Contract.Assert(day != upperBoundNewYearDay);
+
+ return day - 1;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs
new file mode 100644
index 0000000000..4cb95fb8f1
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs
@@ -0,0 +1,339 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+// Purpose: This class implements a set of methods for retrieving
+// character type information. Character type information is
+// independent of culture and region.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Threading;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Reflection;
+using System.Security;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ public static partial class CharUnicodeInfo
+ {
+ //--------------------------------------------------------------------//
+ // Internal Information //
+ //--------------------------------------------------------------------//
+
+ //
+ // Native methods to access the Unicode category data tables in charinfo.nlp.
+ //
+ internal const char HIGH_SURROGATE_START = '\ud800';
+ internal const char HIGH_SURROGATE_END = '\udbff';
+ internal const char LOW_SURROGATE_START = '\udc00';
+ internal const char LOW_SURROGATE_END = '\udfff';
+
+ internal const int UNICODE_CATEGORY_OFFSET = 0;
+ internal const int BIDI_CATEGORY_OFFSET = 1;
+
+
+
+ // The starting codepoint for Unicode plane 1. Plane 1 contains 0x010000 ~ 0x01ffff.
+ internal const int UNICODE_PLANE01_START = 0x10000;
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Actions:
+ // Convert the BMP character or surrogate pointed by index to a UTF32 value.
+ // This is similar to Char.ConvertToUTF32, but the difference is that
+ // it does not throw exceptions when invalid surrogate characters are passed in.
+ //
+ // WARNING: since it doesn't throw an exception it CAN return a value
+ // in the surrogate range D800-DFFF, which are not legal unicode values.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static int InternalConvertToUtf32(String s, int index)
+ {
+ Contract.Assert(s != null, "s != null");
+ Contract.Assert(index >= 0 && index < s.Length, "index < s.Length");
+ if (index < s.Length - 1)
+ {
+ int temp1 = (int)s[index] - HIGH_SURROGATE_START;
+ if (temp1 >= 0 && temp1 <= 0x3ff)
+ {
+ int temp2 = (int)s[index + 1] - LOW_SURROGATE_START;
+ if (temp2 >= 0 && temp2 <= 0x3ff)
+ {
+ // Convert the surrogate to UTF32 and get the result.
+ return ((temp1 * 0x400) + temp2 + UNICODE_PLANE01_START);
+ }
+ }
+ }
+ return ((int)s[index]);
+ }
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Convert a character or a surrogate pair starting at index of string s
+ // to UTF32 value.
+ //
+ // Parameters:
+ // s The string
+ // index The starting index. It can point to a BMP character or
+ // a surrogate pair.
+ // len The length of the string.
+ // charLength [out] If the index points to a BMP char, charLength
+ // will be 1. If the index points to a surrogate pair,
+ // charLength will be 2.
+ //
+ // WARNING: since it doesn't throw an exception it CAN return a value
+ // in the surrogate range D800-DFFF, which are not legal unicode values.
+ //
+ // Returns:
+ // The UTF32 value
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static int InternalConvertToUtf32(String s, int index, out int charLength)
+ {
+ Contract.Assert(s != null, "s != null");
+ Contract.Assert(s.Length > 0, "s.Length > 0");
+ Contract.Assert(index >= 0 && index < s.Length, "index >= 0 && index < s.Length");
+ charLength = 1;
+ if (index < s.Length - 1)
+ {
+ int temp1 = (int)s[index] - HIGH_SURROGATE_START;
+ if (temp1 >= 0 && temp1 <= 0x3ff)
+ {
+ int temp2 = (int)s[index + 1] - LOW_SURROGATE_START;
+ if (temp2 >= 0 && temp2 <= 0x3ff)
+ {
+ // Convert the surrogate to UTF32 and get the result.
+ charLength++;
+ return ((temp1 * 0x400) + temp2 + UNICODE_PLANE01_START);
+ }
+ }
+ }
+ return ((int)s[index]);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsWhiteSpace
+ //
+ // Determines if the given character is a white space character.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static bool IsWhiteSpace(String s, int index)
+ {
+ Contract.Assert(s != null, "s!=null");
+ Contract.Assert(index >= 0 && index < s.Length, "index >= 0 && index < s.Length");
+
+ UnicodeCategory uc = GetUnicodeCategory(s, index);
+ // In Unicode 3.0, U+2028 is the only character which is under the category "LineSeparator".
+ // And U+2029 is th eonly character which is under the category "ParagraphSeparator".
+ switch (uc)
+ {
+ case (UnicodeCategory.SpaceSeparator):
+ case (UnicodeCategory.LineSeparator):
+ case (UnicodeCategory.ParagraphSeparator):
+ return (true);
+ }
+ return (false);
+ }
+
+
+ internal static bool IsWhiteSpace(char c)
+ {
+ UnicodeCategory uc = GetUnicodeCategory(c);
+ // In Unicode 3.0, U+2028 is the only character which is under the category "LineSeparator".
+ // And U+2029 is th eonly character which is under the category "ParagraphSeparator".
+ switch (uc)
+ {
+ case (UnicodeCategory.SpaceSeparator):
+ case (UnicodeCategory.LineSeparator):
+ case (UnicodeCategory.ParagraphSeparator):
+ return (true);
+ }
+
+ return (false);
+ }
+
+
+ //
+ // This is called by the public char and string, index versions
+ //
+ // Note that for ch in the range D800-DFFF we just treat it as any other non-numeric character
+ //
+ internal unsafe static double InternalGetNumericValue(int ch)
+ {
+ Contract.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range.");
+ // Get the level 2 item from the highest 12 bit (8 - 19) of ch.
+ ushort index = s_pNumericLevel1Index[ch >> 8];
+ // Get the level 2 WORD offset from the 4 - 7 bit of ch. This provides the base offset of the level 3 table.
+ // The offset is referred to an float item in m_pNumericFloatData.
+ // Note that & has the lower precedence than addition, so don't forget the parathesis.
+ index = s_pNumericLevel1Index[index + ((ch >> 4) & 0x000f)];
+
+ fixed (ushort* pUshortPtr = &(s_pNumericLevel1Index[index]))
+ {
+ byte* pBytePtr = (byte*)pUshortPtr;
+ fixed (byte* pByteNum = s_pNumericValues)
+ {
+ double* pDouble = (double*)pByteNum;
+ return pDouble[pBytePtr[(ch & 0x000f)]];
+ }
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //Returns the numeric value associated with the character c. If the character is a fraction,
+ // the return value will not be an integer. If the character does not have a numeric value, the return value is -1.
+ //
+ //Returns:
+ // the numeric value for the specified Unicode character. If the character does not have a numeric value, the return value is -1.
+ //Arguments:
+ // ch a Unicode character
+ //Exceptions:
+ // ArgumentNullException
+ // ArgumentOutOfRangeException
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public static double GetNumericValue(char ch)
+ {
+ return (InternalGetNumericValue(ch));
+ }
+
+
+ public static double GetNumericValue(String s, int index)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException("s");
+ }
+ if (index < 0 || index >= s.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_Index);
+ }
+ Contract.EndContractBlock();
+ return (InternalGetNumericValue(InternalConvertToUtf32(s, index)));
+ }
+
+ public static UnicodeCategory GetUnicodeCategory(char ch)
+ {
+ return (InternalGetUnicodeCategory(ch));
+ }
+
+ public static UnicodeCategory GetUnicodeCategory(String s, int index)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+ if (((uint)index) >= ((uint)s.Length))
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ Contract.EndContractBlock();
+ return InternalGetUnicodeCategory(s, index);
+ }
+
+ internal unsafe static UnicodeCategory InternalGetUnicodeCategory(int ch)
+ {
+ return ((UnicodeCategory)InternalGetCategoryValue(ch, UNICODE_CATEGORY_OFFSET));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //Action: Returns the Unicode Category property for the character c.
+ //Returns:
+ // an value in UnicodeCategory enum
+ //Arguments:
+ // ch a Unicode character
+ //Exceptions:
+ // None
+ //
+ //Note that this API will return values for D800-DF00 surrogate halves.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal unsafe static byte InternalGetCategoryValue(int ch, int offset)
+ {
+ Contract.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range.");
+ // Get the level 2 item from the highest 12 bit (8 - 19) of ch.
+ ushort index = s_pCategoryLevel1Index[ch >> 8];
+ // Get the level 2 WORD offset from the 4 - 7 bit of ch. This provides the base offset of the level 3 table.
+ // Note that & has the lower precedence than addition, so don't forget the parathesis.
+ index = s_pCategoryLevel1Index[index + ((ch >> 4) & 0x000f)];
+
+ fixed (ushort* pUshortPtr = &(s_pCategoryLevel1Index[index]))
+ {
+ byte* pBytePtr = (byte*)pUshortPtr;
+ // Get the result from the 0 -3 bit of ch.
+ byte valueIndex = pBytePtr[(ch & 0x000f)];
+ byte uc = s_pCategoriesValue[valueIndex * 2 + offset];
+ //
+ // Make sure that OtherNotAssigned is the last category in UnicodeCategory.
+ // If that changes, change the following assertion as well.
+ //
+ //Contract.Assert(uc >= 0 && uc <= UnicodeCategory.OtherNotAssigned, "Table returns incorrect Unicode category");
+ return (uc);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //Action: Returns the Unicode Category property for the character c.
+ //Returns:
+ // an value in UnicodeCategory enum
+ //Arguments:
+ // value a Unicode String
+ // index Index for the specified string.
+ //Exceptions:
+ // None
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static UnicodeCategory InternalGetUnicodeCategory(String value, int index)
+ {
+ Contract.Assert(value != null, "value can not be null");
+ Contract.Assert(index < value.Length, "index < value.Length");
+
+ return (InternalGetUnicodeCategory(InternalConvertToUtf32(value, index)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the Unicode category of the character starting at index. If the character is in BMP, charLength will return 1.
+ // If the character is a valid surrogate pair, charLength will return 2.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static UnicodeCategory InternalGetUnicodeCategory(String str, int index, out int charLength)
+ {
+ Contract.Assert(str != null, "str can not be null");
+ Contract.Assert(str.Length > 0, "str.Length > 0"); ;
+ Contract.Assert(index >= 0 && index < str.Length, "index >= 0 && index < str.Length");
+
+ return (InternalGetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength)));
+ }
+
+ internal static bool IsCombiningCategory(UnicodeCategory uc)
+ {
+ Contract.Assert(uc >= 0, "uc >= 0");
+ return (
+ uc == UnicodeCategory.NonSpacingMark ||
+ uc == UnicodeCategory.SpacingCombiningMark ||
+ uc == UnicodeCategory.EnclosingMark
+ );
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs
new file mode 100644
index 0000000000..7284cfd3bc
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs
@@ -0,0 +1,1222 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ public static partial class CharUnicodeInfo
+ {
+ // THE FOLLOWING DATA IS AUTO GENERATED BY GenUnicodeProp.pl SCRIPT UNDER THE TOOLS FOLDER
+ // PLEASE DON'T MODIFY BY HAND
+
+
+ // 12:4:4 index table of the Unicode cateogry data.
+ private static ushort[] s_pCategoryLevel1Index = new ushort[]
+ {
+ 0x1100, 0x1110, 0x1120, 0x1130, 0x1140, 0x1150, 0x1160, 0x1170, 0x1180, 0x1190, 0x11a0, 0x11b0, 0x11c0, 0x11d0, 0x11e0, 0x11f0,
+ 0x1200, 0x1210, 0x1220, 0x1230, 0x1240, 0x1210, 0x1250, 0x1260, 0x1270, 0x1280, 0x1290, 0x12a0, 0x12b0, 0x12c0, 0x12d0, 0x12e0,
+ 0x12f0, 0x1300, 0x1310, 0x1320, 0x1330, 0x1340, 0x1350, 0x1360, 0x1370, 0x1380, 0x1390, 0x13a0, 0x13b0, 0x13c0, 0x13d0, 0x13e0,
+ 0x13f0, 0x1400, 0x1410, 0x1420, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1430, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1440,
+ 0x1450, 0x1210, 0x1210, 0x1210, 0x1460, 0x1210, 0x1470, 0x1480, 0x1490, 0x14a0, 0x14b0, 0x14c0, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x14d0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x1210, 0x1500, 0x1510, 0x1520, 0x1530, 0x1540, 0x1550,
+ 0x1560, 0x1570, 0x1580, 0x1590, 0x15a0, 0x15b0, 0x1210, 0x15c0, 0x15d0, 0x15e0, 0x15f0, 0x1600, 0x1610, 0x1620, 0x1630, 0x1620,
+ 0x1640, 0x1650, 0x1660, 0x1670, 0x1680, 0x1690, 0x16a0, 0x16b0, 0x16c0, 0x1620, 0x16d0, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1210, 0x1210, 0x1210, 0x16e0, 0x16f0, 0x1700, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1710, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1210, 0x1210, 0x1720, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1210, 0x1210, 0x1730, 0x1740, 0x1620, 0x1620, 0x1620, 0x1750,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1760, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1770, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1780, 0x1790, 0x17a0, 0x17b0, 0x17c0, 0x17d0, 0x17e0, 0x17f0, 0x1370, 0x1370, 0x1800, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1810, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1820, 0x1620,
+ 0x1830, 0x1840, 0x1850, 0x1860, 0x1870, 0x1880, 0x1890, 0x18a0, 0x18b0, 0x18c0, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x18d0, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x18e0, 0x18f0, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1900, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1210, 0x1210, 0x1910, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1920, 0x1930, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x1940,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x1940,
+ 0x1950, 0x1958, 0x1960, 0x1968, 0x1970, 0x1978, 0x1980, 0x1988, 0x1990, 0x1998, 0x19a0, 0x19a8, 0x19b0, 0x19b8, 0x19c0, 0x19c8,
+ 0x19d0, 0x19d0, 0x19d0, 0x19d8, 0x19e0, 0x19d0, 0x19d0, 0x19e8, 0x19f0, 0x19f8, 0x1a00, 0x1a08, 0x1a10, 0x1a18, 0x19d0, 0x1a20,
+ 0x19d0, 0x19d0, 0x19d0, 0x1a28, 0x1a30, 0x19c0, 0x19c0, 0x19c0, 0x19c0, 0x1a38, 0x19c0, 0x1a40, 0x1a48, 0x1a50, 0x1a58, 0x1a60,
+ 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a70, 0x1a78, 0x1a80, 0x1a88, 0x19c0, 0x1a90, 0x1a98, 0x19d0, 0x1aa0,
+ 0x19b0, 0x19b0, 0x19b0, 0x19c0, 0x19c0, 0x19c0, 0x19d0, 0x19d0, 0x1aa8, 0x19d0, 0x19d0, 0x19d0, 0x1ab0, 0x19d0, 0x19d0, 0x19d0,
+ 0x19d0, 0x19d0, 0x19d0, 0x1ab8, 0x19b0, 0x1ac0, 0x1ac8, 0x19c0, 0x1ad0, 0x1ad8, 0x1a68, 0x1ae0, 0x1ae8, 0x1af0, 0x1af8, 0x1b00,
+ 0x1b08, 0x1b10, 0x1b18, 0x1b18, 0x1b20, 0x1a68, 0x1b28, 0x1b30, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b38, 0x1b40, 0x1b48,
+ 0x1b50, 0x1b58, 0x1b18, 0x1a68, 0x1b60, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b68, 0x1b70, 0x1b78, 0x1af0, 0x1b80, 0x1b88,
+ 0x1af0, 0x1b90, 0x1b98, 0x1ba0, 0x1af0, 0x1ba8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1b18, 0x1bb8, 0x1bb0, 0x1bb0, 0x1bc0, 0x1a68,
+ 0x1bc8, 0x1bd0, 0x1bd0, 0x1bd8, 0x1be0, 0x1be8, 0x1bf0, 0x1bf8, 0x1c00, 0x1c08, 0x1c10, 0x1c18, 0x1c20, 0x1c28, 0x1c30, 0x1c38,
+ 0x1c40, 0x1c08, 0x1c10, 0x1c48, 0x1c50, 0x1c58, 0x1c60, 0x1c68, 0x1c70, 0x1c78, 0x1c10, 0x1c80, 0x1c88, 0x1c90, 0x1c30, 0x1c98,
+ 0x1ca0, 0x1c08, 0x1c10, 0x1ca8, 0x1cb0, 0x1cb8, 0x1c30, 0x1cc0, 0x1cc8, 0x1cd0, 0x1cd8, 0x1ce0, 0x1ce8, 0x1cf0, 0x1c60, 0x1cf8,
+ 0x1d00, 0x1d08, 0x1c10, 0x1d10, 0x1d18, 0x1d20, 0x1c30, 0x1d28, 0x1d30, 0x1d08, 0x1c10, 0x1d38, 0x1d40, 0x1d48, 0x1c30, 0x1d50,
+ 0x1d30, 0x1d08, 0x1bd0, 0x1d58, 0x1d60, 0x1d68, 0x1c30, 0x1d70, 0x1d78, 0x1d80, 0x1bd0, 0x1d88, 0x1d90, 0x1d98, 0x1c60, 0x1da0,
+ 0x1da8, 0x1bd0, 0x1bd0, 0x1db0, 0x1db8, 0x1dc0, 0x1bb0, 0x1bb0, 0x1dc8, 0x1dd0, 0x1dd8, 0x1de0, 0x1de8, 0x1df0, 0x1bb0, 0x1bb0,
+ 0x1df8, 0x1e00, 0x1e08, 0x1e10, 0x1e18, 0x1bd0, 0x1e20, 0x1e28, 0x1e30, 0x1e38, 0x1a68, 0x1e40, 0x1e48, 0x1e50, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1e58, 0x1e60, 0x1e68, 0x1e70, 0x1e78, 0x1e80, 0x1e88, 0x1e90, 0x19b0, 0x19b0, 0x1e98, 0x1bd0, 0x1bd0, 0x1ea0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1ea8, 0x1eb0, 0x1bd0, 0x1bd0, 0x1ea8, 0x1bd0, 0x1bd0, 0x1eb8, 0x1ec0, 0x1ec8, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1ec0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1ed0, 0x1ed8, 0x1ee0, 0x1bd0, 0x1ee8, 0x19b0, 0x19b0, 0x19b0, 0x19b0, 0x19b0, 0x1ef0,
+ 0x1ef8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f00, 0x1bd0, 0x1f08, 0x1f10, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f18, 0x1f20,
+ 0x1f28, 0x1f30, 0x1bd0, 0x1f38, 0x1bd0, 0x1f40, 0x1f28, 0x1f48, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f50, 0x1f58, 0x1f60, 0x1f68, 0x1f70,
+ 0x1f78, 0x1f68, 0x1bd0, 0x1bd0, 0x1f80, 0x1bd0, 0x1bd0, 0x1f88, 0x1bd0, 0x1bd0, 0x1f90, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f98,
+ 0x1bd0, 0x1fa0, 0x1fa8, 0x1fb0, 0x1fb8, 0x1bd0, 0x1fc0, 0x1fc8, 0x1bd0, 0x1bd0, 0x1fd0, 0x1bd0, 0x1fd8, 0x1fe0, 0x1fe8, 0x1fe8,
+ 0x1bd0, 0x1ff0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1ff8, 0x2000, 0x2008, 0x1f68, 0x1f68, 0x2010, 0x2018, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2020, 0x1bd0, 0x1bd0, 0x2028, 0x2030, 0x1e68, 0x2038, 0x2040, 0x2048, 0x1bd0, 0x2050, 0x2058, 0x1bd0, 0x1bd0, 0x2060, 0x2068,
+ 0x1bd0, 0x1bd0, 0x2070, 0x2078, 0x2080, 0x2058, 0x1bd0, 0x2088, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2090, 0x2098, 0x20a0, 0x20a8,
+ 0x19c0, 0x19c0, 0x20b0, 0x20b8, 0x20b8, 0x20b8, 0x20c0, 0x20c8, 0x19c0, 0x20d0, 0x20b8, 0x20b8, 0x1a68, 0x1a68, 0x1a68, 0x20d8,
+ 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x20e0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0,
+ 0x20e8, 0x20f0, 0x20e8, 0x20e8, 0x20f0, 0x20f8, 0x20e8, 0x2100, 0x2108, 0x2108, 0x2108, 0x2110, 0x2118, 0x2120, 0x2128, 0x2130,
+ 0x2138, 0x2140, 0x2148, 0x2150, 0x2158, 0x2160, 0x2168, 0x2170, 0x2178, 0x2180, 0x2188, 0x2190, 0x1bb0, 0x2198, 0x21a0, 0x21a8,
+ 0x21b0, 0x21b8, 0x21c0, 0x21c8, 0x21d0, 0x21d8, 0x21e0, 0x21e0, 0x21e8, 0x21f0, 0x21f8, 0x1fe8, 0x2200, 0x2208, 0x1fe8, 0x2210,
+ 0x2218, 0x2220, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218,
+ 0x2228, 0x1fe8, 0x2230, 0x2238, 0x2240, 0x2240, 0x2240, 0x2248, 0x1fe8, 0x2250, 0x2218, 0x2258, 0x1fe8, 0x2260, 0x2268, 0x2270,
+ 0x1fe8, 0x1fe8, 0x2278, 0x1bb0, 0x2270, 0x1bb0, 0x21d8, 0x21d8, 0x2280, 0x2288, 0x2240, 0x2240, 0x2240, 0x2240, 0x2290, 0x21d8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2298, 0x22a0, 0x1fe8, 0x1fe8, 0x22a8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x22b0, 0x1fe8, 0x1fe8, 0x1fe8, 0x22b8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x22c0, 0x22c8, 0x21d8, 0x22d0, 0x1fe8, 0x1fe8, 0x22d8, 0x2218, 0x22e0, 0x2218,
+ 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240,
+ 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x22e8, 0x22f0, 0x2218, 0x2218, 0x2218, 0x22f8, 0x2218, 0x2300,
+ 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x2218, 0x2308, 0x1fe8, 0x1fe8, 0x2310, 0x1fe8, 0x2318, 0x1fe8, 0x2320, 0x2328, 0x2330, 0x2338, 0x1bb0,
+ 0x19b0, 0x19b0, 0x2340, 0x19c0, 0x19c0, 0x2348, 0x2350, 0x2358, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x2360, 0x2368,
+ 0x19c0, 0x19c0, 0x2370, 0x1bd0, 0x1bd0, 0x1bd0, 0x2378, 0x2380, 0x1bd0, 0x2388, 0x2390, 0x2390, 0x2390, 0x2390, 0x1a68, 0x1a68,
+ 0x2398, 0x23a0, 0x23a8, 0x23b0, 0x23b8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1fe8, 0x23c0, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23d0, 0x1bb0, 0x23d8,
+ 0x23e0, 0x23e8, 0x23f0, 0x23f8, 0x1da8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2400, 0x1ef8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2408,
+ 0x2410, 0x1bd0, 0x1fc0, 0x1da8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fa0, 0x2418, 0x1bd0, 0x2420, 0x1fe8, 0x1fe8, 0x23c8, 0x1bd0,
+ 0x2240, 0x2428, 0x2430, 0x2240, 0x2438, 0x2440, 0x2240, 0x2448, 0x2430, 0x2240, 0x2240, 0x2450, 0x2458, 0x2240, 0x2240, 0x2460,
+ 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2468, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2470, 0x2240, 0x2478,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f98, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f98, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x2480, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1e20, 0x1fe8, 0x1fe8, 0x1fe8, 0x2278, 0x1bd0, 0x1bd0, 0x2088,
+ 0x2488, 0x1bd0, 0x2490, 0x1bb0, 0x19d0, 0x19d0, 0x2498, 0x24a0, 0x19d0, 0x24a8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x24b0, 0x24b8,
+ 0x1a60, 0x24c0, 0x24c8, 0x24d0, 0x19d0, 0x19d0, 0x19d0, 0x24d8, 0x24e0, 0x24e8, 0x24f0, 0x24f8, 0x1bb0, 0x1bb0, 0x1bb0, 0x2500,
+ 0x2508, 0x1bd0, 0x2510, 0x2518, 0x1bd0, 0x1bd0, 0x1bd0, 0x2520, 0x2528, 0x1bd0, 0x1bd0, 0x2530, 0x2538, 0x1f68, 0x1a68, 0x2540,
+ 0x2058, 0x1bd0, 0x2548, 0x1bd0, 0x2550, 0x2558, 0x1bd0, 0x1e20, 0x1bc8, 0x1bd0, 0x1bd0, 0x2560, 0x2568, 0x2570, 0x2578, 0x2580,
+ 0x1bd0, 0x1bd0, 0x2588, 0x2590, 0x2598, 0x25a0, 0x1bd0, 0x25a8, 0x1bd0, 0x1bd0, 0x1bd0, 0x25b0, 0x25b8, 0x25c0, 0x25c8, 0x25d0,
+ 0x25d8, 0x25e0, 0x2390, 0x19c0, 0x19c0, 0x25e8, 0x25f0, 0x19c0, 0x19c0, 0x19c0, 0x19c0, 0x19c0, 0x1bd0, 0x1bd0, 0x25f8, 0x1f68,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2600, 0x1bd0, 0x2608, 0x1bd0, 0x1bd0, 0x1fd0,
+ 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610,
+ 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fd8, 0x1bb0, 0x1bb0,
+ 0x2620, 0x2628, 0x2630, 0x2638, 0x2640, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x2648, 0x2650, 0x2658, 0x1b18, 0x1b18,
+ 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18,
+ 0x1b18, 0x1b18, 0x1b18, 0x2660, 0x1bb0, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x2668, 0x1b18, 0x1b18, 0x2670, 0x1bb0, 0x1bb0, 0x2678,
+ 0x1a68, 0x2680, 0x1a68, 0x2688, 0x2690, 0x2698, 0x26a0, 0x26a8, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x26b0,
+ 0x26b8, 0x1968, 0x1970, 0x1978, 0x1980, 0x26c0, 0x26c8, 0x26d0, 0x1bd0, 0x26d8, 0x1bd0, 0x1fa0, 0x26e0, 0x26e8, 0x26f0, 0x26f8,
+ 0x2700, 0x1bd0, 0x1ec8, 0x2708, 0x1fc0, 0x1fc0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2420,
+ 0x2710, 0x2718, 0x2718, 0x2720, 0x2728, 0x2728, 0x2728, 0x2730, 0x2738, 0x23d8, 0x2740, 0x1bb0, 0x1bb0, 0x2240, 0x2240, 0x2748,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1e20, 0x1bd0, 0x1bd0, 0x1bd0, 0x1c90, 0x2750, 0x2758,
+ 0x1bd0, 0x1bd0, 0x2760, 0x1bd0, 0x2768, 0x1bd0, 0x1bd0, 0x2770, 0x1bd0, 0x2778, 0x1bd0, 0x1bd0, 0x2780, 0x2788, 0x1bb0, 0x1bb0,
+ 0x19b0, 0x19b0, 0x2790, 0x19c0, 0x19c0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc0, 0x1f68, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1f88, 0x1bd0, 0x1bd0, 0x1bd0, 0x2798, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x2388, 0x1bd0, 0x1f98, 0x1f88, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x27a0, 0x1af0, 0x1af0, 0x27a8, 0x1af0, 0x27b0, 0x1af0, 0x27b8, 0x1af0, 0x27c0, 0x27c8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1af0, 0x27d0,
+ 0x1af0, 0x27d8, 0x1af0, 0x27e0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1af0, 0x1af0, 0x1af0, 0x27e8, 0x27f0, 0x27f8, 0x27f0, 0x27f0,
+ 0x2800, 0x2808, 0x1af0, 0x2810, 0x2818, 0x2820, 0x1af0, 0x2828, 0x1af0, 0x2830, 0x1bb0, 0x1bb0, 0x2838, 0x1af0, 0x2840, 0x2848,
+ 0x1af0, 0x1af0, 0x1af0, 0x2850, 0x1af0, 0x2858, 0x1af0, 0x2860, 0x1af0, 0x2868, 0x2870, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x2878, 0x1bb0, 0x1bb0, 0x1bb0, 0x2880, 0x2880, 0x2880, 0x2888, 0x2890, 0x2890, 0x2890, 0x2898,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x28a0, 0x28a8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x28b0, 0x1bd0, 0x1bd0, 0x28b8, 0x28c0, 0x28c8, 0x28d0, 0x28d8, 0x2048, 0x1bd0, 0x1bd0, 0x28e0, 0x28e8, 0x1bd0, 0x28f0, 0x1f68,
+ 0x28f8, 0x1bd0, 0x2900, 0x2908, 0x2910, 0x1bd0, 0x1bd0, 0x2918, 0x2048, 0x1bd0, 0x1bd0, 0x2920, 0x2928, 0x2930, 0x2938, 0x2940,
+ 0x1bd0, 0x1c78, 0x2948, 0x2950, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2958, 0x2960, 0x2968, 0x1bd0, 0x1bd0, 0x2970, 0x2978, 0x1f68,
+ 0x2980, 0x1c08, 0x1c10, 0x1c80, 0x2988, 0x2990, 0x2998, 0x29a0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x1bd0, 0x29a8, 0x29b0, 0x1f68, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x29b8, 0x29c0, 0x29c8, 0x29d0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x29d8, 0x29e0, 0x1f68, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x29e8, 0x29f0, 0x1f68, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x29f8, 0x2a00, 0x2a08, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x19b0, 0x19b0, 0x19c0, 0x19c0, 0x1e08, 0x2a10,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x1bd0, 0x28f0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fd8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x21e0, 0x21e0, 0x21e0, 0x21e0, 0x21e0, 0x21e0, 0x2a18, 0x2a20, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2600, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1fa0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2388, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x28f0, 0x1bd0, 0x1fa0, 0x2570, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1fc0, 0x2a28,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x2a30, 0x2a38, 0x2a40, 0x2a48, 0x2a50, 0x1bd0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc8, 0x2a58, 0x2a60, 0x2a68, 0x28d8, 0x2a70, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2a78, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2420, 0x1e20, 0x28f0, 0x2a80, 0x2a88, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2a90,
+ 0x2240, 0x2240, 0x2a98, 0x2240, 0x2240, 0x2240, 0x2aa0, 0x2aa8, 0x2ab0, 0x2240, 0x2ab8, 0x2240, 0x2240, 0x2240, 0x2ac0, 0x1bb0,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2ac8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2278, 0x2718, 0x2ad0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x19b0, 0x2ad8, 0x19c0, 0x2ae0, 0x2ae8, 0x2af0, 0x20e8, 0x19b0, 0x2af8, 0x2b00, 0x2b08, 0x2b10, 0x2b18, 0x19b0, 0x2ad8, 0x19c0,
+ 0x2b20, 0x2b28, 0x19c0, 0x2b30, 0x2b38, 0x2b40, 0x2b48, 0x19b0, 0x2b50, 0x19c0, 0x19b0, 0x2ad8, 0x19c0, 0x2ae0, 0x2ae8, 0x19c0,
+ 0x20e8, 0x19b0, 0x2af8, 0x2b48, 0x19b0, 0x2b50, 0x19c0, 0x19b0, 0x2ad8, 0x19c0, 0x2b58, 0x19b0, 0x2b60, 0x2b68, 0x2b70, 0x2b78,
+ 0x19c0, 0x2b80, 0x19b0, 0x2b88, 0x2b90, 0x2b98, 0x2ba0, 0x19c0, 0x2ba8, 0x19b0, 0x2bb0, 0x19c0, 0x2bb8, 0x2bc0, 0x2bc0, 0x2bc0,
+ 0x1a68, 0x1a68, 0x1a68, 0x2bc8, 0x1a68, 0x1a68, 0x2bd0, 0x2bd8, 0x2be0, 0x2be8, 0x1ad8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x2bf0, 0x2bf8, 0x1bb0, 0x1bb0,
+ 0x2c00, 0x1b18, 0x2c08, 0x2c10, 0x2c18, 0x2c20, 0x2c28, 0x2c30, 0x2c38, 0x2c40, 0x2c48, 0x2c40, 0x1bb0, 0x1bb0, 0x1bb0, 0x2c50,
+ 0x1fe8, 0x1fe8, 0x23d8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c8, 0x2c58, 0x2c60, 0x2c60, 0x2c60, 0x1fe8, 0x23d0,
+ 0x2c68, 0x2240, 0x2460, 0x2240, 0x2240, 0x2240, 0x2c70, 0x2240, 0x2240, 0x2c78, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2c80, 0x2240,
+ 0x2c88, 0x2240, 0x2240, 0x2c78, 0x2ac0, 0x2c90, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2c98,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c0, 0x1fe8, 0x1fe8, 0x2ca0, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2740, 0x2ca8, 0x23c8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2cb0, 0x1bb0, 0x1bb0,
+ 0x23d8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2cb8, 0x1ee8, 0x1fe8, 0x1fe8, 0x2cb8, 0x1fe8, 0x2cc0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x2cc8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2cb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2740, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2388, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1fc0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2a78, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1fc0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2cd0, 0x1bb0, 0x2cd8, 0x2cd8, 0x2cd8, 0x2cd8, 0x2cd8, 0x2cd8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1bb0,
+ 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2ce0,
+ 0x0101, 0x0101, 0x0101, 0x0101, 0x0201, 0x0203, 0x0304, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0303, 0x0203,
+ 0x0605, 0x0706, 0x0708, 0x0606, 0x0a09, 0x0b06, 0x0d0c, 0x0c0c, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x060c, 0x0f0f, 0x060f,
+ 0x1006, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x0910, 0x0a06, 0x1211,
+ 0x1311, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0913, 0x0a0f, 0x010f,
+ 0x0101, 0x0101, 0x0301, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+ 0x0614, 0x0808, 0x0808, 0x0615, 0x1511, 0x1716, 0x180f, 0x1115, 0x1a19, 0x1b1b, 0x1311, 0x0606, 0x1b11, 0x1c16, 0x1d1d, 0x061d,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x0f10, 0x1010, 0x1010, 0x1010, 0x1310,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1013, 0x1013, 0x1013, 0x1013,
+ 0x1013, 0x1013, 0x1013, 0x1013, 0x1313, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1010, 0x1013, 0x1013, 0x1313,
+ 0x1013, 0x1310, 0x1310, 0x1010, 0x1013, 0x1010, 0x1313, 0x1010, 0x1010, 0x1013, 0x1310, 0x1010, 0x1310, 0x1313, 0x1010, 0x1013,
+ 0x1310, 0x1310, 0x1310, 0x1010, 0x1013, 0x1313, 0x1310, 0x1010, 0x1013, 0x1010, 0x1013, 0x1013, 0x1310, 0x1613, 0x1310, 0x1313,
+ 0x1616, 0x1616, 0x1e10, 0x1013, 0x131e, 0x1e10, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1313, 0x1310,
+ 0x1013, 0x131e, 0x1310, 0x1010, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1313, 0x1313, 0x1313, 0x1010, 0x1013, 0x1310,
+ 0x1013, 0x1013, 0x1010, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1313, 0x1313, 0x1316, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x201f, 0x1f20, 0x1f1f, 0x1f1f, 0x1f1f, 0x1111, 0x1111, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020,
+ 0x1f1f, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1f1f, 0x1f1f, 0x111f, 0x1111, 0x1111, 0x1111, 0x1120, 0x111f,
+ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x1310, 0x1310, 0x1120, 0x1310, 0x0000, 0x131f, 0x1313, 0x1006, 0x0000, 0x0000, 0x1111, 0x0610, 0x1010, 0x0010, 0x0010, 0x1010,
+ 0x1013, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1013, 0x1313, 0x1010, 0x1310, 0x1313, 0x1310, 0x1310, 0x1310, 0x1310,
+ 0x1313, 0x1313, 0x1310, 0x100f, 0x1013, 0x1310, 0x1013, 0x1010, 0x1310, 0x2122, 0x2121, 0x2121, 0x2323, 0x1310, 0x1310, 0x1310,
+ 0x1010, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1313, 0x1000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x0010, 0x1f00, 0x2424, 0x2424, 0x2424, 0x1300, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x2400, 0x0025, 0x1500, 0x0815, 0x2100, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2126, 0x2127, 0x2721, 0x2121, 0x2127, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x0000, 0x0000,
+ 0x2828, 0x2728, 0x0027, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2929, 0x2929, 0x2929, 0x0f0f, 0x072a, 0x2b07, 0x2c0c, 0x1515,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2c21, 0x002d, 0x2c2c, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2f, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x212e, 0x2121, 0x2121, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3107, 0x2c31, 0x2e2e,
+ 0x2e21, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2c, 0x2121, 0x2121, 0x2121, 0x2921, 0x2115,
+ 0x2121, 0x2121, 0x2f21, 0x212f, 0x1521, 0x2121, 0x2121, 0x2e2e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x2e2e, 0x322e, 0x2e32,
+ 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2d00, 0x212e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x2e21, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x2828, 0x2828, 0x2828,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2128, 0x2121, 0x2121, 0x2121, 0x2121, 0x3434, 0x0615, 0x0606, 0x0034, 0x0000, 0x0000,
+ 0x2828, 0x2828, 0x2828, 0x2121, 0x2121, 0x2134, 0x2121, 0x2121, 0x2121, 0x2121, 0x2134, 0x2121, 0x2134, 0x2121, 0x2121, 0x0000,
+ 0x2727, 0x2727, 0x2727, 0x2727, 0x2727, 0x2727, 0x2727, 0x0027, 0x2828, 0x2828, 0x2828, 0x2828, 0x2128, 0x2121, 0x0000, 0x0027,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2e2e, 0x2e2e, 0x002e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2100, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x3521, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x1621, 0x3535,
+ 0x2135, 0x2121, 0x2121, 0x2121, 0x3521, 0x3535, 0x2135, 0x3535, 0x2116, 0x2121, 0x2121, 0x2121, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x2121, 0x2424, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1f24, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x2116, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x0016, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x0016, 0x0016, 0x0000, 0x1616, 0x1616, 0x0000, 0x1621, 0x3535,
+ 0x2135, 0x2121, 0x0021, 0x3500, 0x0035, 0x3500, 0x2135, 0x0016, 0x0000, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x1616, 0x1600,
+ 0x1616, 0x2121, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x0808, 0x3737, 0x3737, 0x3737, 0x0822, 0x0000, 0x0000,
+ 0x2100, 0x3521, 0x1600, 0x1616, 0x1616, 0x0016, 0x0000, 0x1600, 0x0016, 0x1616, 0x1600, 0x0016, 0x1616, 0x0000, 0x0021, 0x3535,
+ 0x2135, 0x0021, 0x0000, 0x2100, 0x0021, 0x2100, 0x2121, 0x0000, 0x2100, 0x0000, 0x0000, 0x0000, 0x1600, 0x1616, 0x0016, 0x0016,
+ 0x0000, 0x0000, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2121, 0x1616, 0x2116, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2100, 0x3521, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x0016, 0x1616, 0x1600, 0x1616, 0x1616, 0x0000, 0x1621, 0x3535, 0x2135, 0x2121, 0x2121, 0x2100, 0x3521, 0x3500, 0x2135, 0x0000,
+ 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0824, 0x0000, 0x0000, 0x0000, 0x1600, 0x0000, 0x0000, 0x0000,
+ 0x2100, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x0016, 0x1616, 0x1600, 0x1616, 0x1616, 0x0000, 0x1621, 0x2135,
+ 0x2135, 0x2121, 0x0021, 0x3500, 0x0035, 0x3500, 0x2135, 0x0000, 0x0000, 0x0000, 0x0000, 0x3521, 0x0000, 0x0000, 0x1616, 0x1600,
+ 0x1622, 0x3737, 0x3737, 0x3737, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1621, 0x1600, 0x1616, 0x1616, 0x0016, 0x0000, 0x1616,
+ 0x0016, 0x1616, 0x1616, 0x0000, 0x1600, 0x0016, 0x0016, 0x1616, 0x0000, 0x1600, 0x0016, 0x0000, 0x1616, 0x0016, 0x0000, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x3535, 0x3521, 0x0035, 0x0000, 0x3535, 0x0035, 0x3535, 0x2135, 0x0000,
+ 0x0016, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x0000, 0x0000, 0x3737, 0x1537, 0x1515, 0x1515, 0x0815, 0x0015, 0x0000, 0x0000,
+ 0x3521, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x1600, 0x2121, 0x3521, 0x3535, 0x0035, 0x2121, 0x0021, 0x2121, 0x2121, 0x0000,
+ 0x0000, 0x0000, 0x2100, 0x0021, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1d1d, 0x1d1d, 0x1d1d, 0x221d,
+ 0x2100, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x0000, 0x1621, 0x3835,
+ 0x3535, 0x3535, 0x0035, 0x3538, 0x0035, 0x3535, 0x2121, 0x0000, 0x0000, 0x0000, 0x3500, 0x0035, 0x0000, 0x0000, 0x0000, 0x0016,
+ 0x1600, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x3535,
+ 0x2135, 0x2121, 0x0021, 0x3535, 0x0035, 0x3535, 0x2135, 0x0016, 0x0000, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x0000, 0x1600,
+ 0x3737, 0x3737, 0x3737, 0x0000, 0x2200, 0x1616, 0x1616, 0x1616, 0x0000, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0021, 0x0000, 0x3500, 0x3535, 0x2121, 0x0021, 0x0021, 0x3535, 0x3535, 0x3535, 0x3535,
+ 0x0000, 0x3535, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x2116, 0x1616, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0800, 0x1616, 0x1616, 0x1616, 0x211f, 0x2121, 0x2121, 0x2121, 0x2421,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2424, 0x0000, 0x0000, 0x1600, 0x0016, 0x0016, 0x1600, 0x0016, 0x0016, 0x1600, 0x0000,
+ 0x0000, 0x0000, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1600, 0x1600, 0x0000, 0x1616, 0x1600, 0x1616,
+ 0x2116, 0x1616, 0x2121, 0x2121, 0x2121, 0x2100, 0x1621, 0x0000, 0x1616, 0x1616, 0x0016, 0x001f, 0x2121, 0x2121, 0x2121, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x1616, 0x1616, 0x2216, 0x2222, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424,
+ 0x2424, 0x2224, 0x2224, 0x2222, 0x2121, 0x2222, 0x2222, 0x2222, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x2122, 0x2122, 0x2122, 0x0a09, 0x0a09, 0x3535, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x2100, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x3521,
+ 0x2121, 0x2121, 0x2421, 0x2121, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2100, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x2222, 0x2222, 0x2222, 0x2222, 0x2221, 0x2222, 0x2222, 0x0022, 0x2222,
+ 0x2424, 0x2424, 0x2224, 0x2222, 0x2422, 0x0024, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3516, 0x2135, 0x2121,
+ 0x3521, 0x2121, 0x2121, 0x2121, 0x2135, 0x3521, 0x2135, 0x1621, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2424, 0x2424, 0x2424,
+ 0x1616, 0x1616, 0x1616, 0x3535, 0x2121, 0x1616, 0x1616, 0x2121, 0x1621, 0x3535, 0x1635, 0x3516, 0x3535, 0x3535, 0x3535, 0x1616,
+ 0x2116, 0x2121, 0x1621, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x2135, 0x3521, 0x3535, 0x3535, 0x2135, 0x3516,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3535, 0x2135, 0x2222, 0x1010, 0x1010, 0x1010, 0x1000, 0x0000, 0x0000, 0x1000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x161f, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x0016, 0x1616, 0x1616, 0x0000, 0x0016, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x0016,
+ 0x0016, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x2100, 0x2121, 0x2424, 0x2424, 0x2424, 0x2424, 0x3724, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x0037, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000,
+ 0x1010, 0x1010, 0x1010, 0x0000, 0x1313, 0x1313, 0x1313, 0x0000, 0x1625, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x1624, 0x1605, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0916, 0x000a, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x2424, 0x3939,
+ 0x1639, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616,
+ 0x1616, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x2121, 0x2421, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x2121, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0016, 0x2121, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x2121, 0x2135, 0x2121, 0x2121, 0x2121, 0x3535, 0x3535, 0x3535, 0x3535, 0x3521, 0x2135, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2424, 0x1f24, 0x2424, 0x0824, 0x2116, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x0000, 0x0000,
+ 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x0000, 0x0000, 0x0000, 0x0606, 0x0606, 0x0606, 0x0625, 0x0606, 0x2106, 0x2121, 0x0018,
+ 0x1616, 0x1f16, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x0016, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x2121, 0x3521, 0x3535, 0x2135, 0x3521, 0x3535, 0x0000, 0x0000,
+ 0x3535, 0x3521, 0x3535, 0x3535, 0x2135, 0x2121, 0x0000, 0x0000, 0x0015, 0x0000, 0x0606, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0037, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1616, 0x1616, 0x1616, 0x2116, 0x3521, 0x2135, 0x0000, 0x2424, 0x1616, 0x1616, 0x3516, 0x3521, 0x2121, 0x2121, 0x2121, 0x0021,
+ 0x3521, 0x3521, 0x2135, 0x2121, 0x2121, 0x2121, 0x3521, 0x3535, 0x3535, 0x2135, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x2100,
+ 0x2424, 0x2424, 0x2424, 0x1f24, 0x2424, 0x2424, 0x2424, 0x0000, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0023,
+ 0x2121, 0x2121, 0x1635, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x2121, 0x2121, 0x3521, 0x3521, 0x3535,
+ 0x3535, 0x3521, 0x1635, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x2224, 0x2222, 0x2222, 0x2222, 0x2222, 0x2122, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x2121, 0x1635, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x3516, 0x2121, 0x2121, 0x3535, 0x2121, 0x2135, 0x2121, 0x1616, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x3521, 0x2121, 0x3535, 0x2135, 0x2135, 0x2121, 0x3535, 0x0000, 0x0000, 0x0000, 0x0000, 0x2424, 0x2424,
+ 0x1616, 0x1616, 0x3535, 0x3535, 0x3535, 0x3535, 0x2121, 0x2121, 0x2121, 0x2121, 0x3535, 0x2121, 0x0000, 0x2400, 0x2424, 0x2424,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1f1f, 0x1f1f, 0x1f1f, 0x2424,
+ 0x2424, 0x2424, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x2121, 0x2421, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x3521, 0x2121, 0x2121, 0x2121, 0x1621, 0x1616, 0x2116, 0x1616, 0x1616, 0x3535, 0x1621, 0x0016, 0x2121, 0x0000, 0x0000, 0x0000,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f,
+ 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x131f, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x131f, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1f13, 0x1f1f, 0x1f1f, 0x2121, 0x2121, 0x2121, 0x0000, 0x0000, 0x0000, 0x2121, 0x2121,
+ 0x1310, 0x1310, 0x1310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x1313, 0x1313, 0x1313, 0x0000, 0x1010, 0x1010, 0x1010, 0x0000, 0x1313, 0x1313, 0x1313, 0x1313, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0000, 0x1313, 0x1313, 0x1313, 0x1313, 0x1e1e, 0x1e1e, 0x1e1e, 0x1e1e,
+ 0x1313, 0x1313, 0x0013, 0x1313, 0x1010, 0x1010, 0x111e, 0x1113, 0x1111, 0x1313, 0x0013, 0x1313, 0x1010, 0x1010, 0x111e, 0x1111,
+ 0x1313, 0x1313, 0x0000, 0x1313, 0x1010, 0x1010, 0x1100, 0x1111, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1110, 0x1111,
+ 0x0000, 0x1313, 0x0013, 0x1313, 0x1010, 0x1010, 0x111e, 0x0011, 0x0505, 0x0505, 0x0505, 0x0505, 0x0505, 0x1805, 0x1818, 0x3b3a,
+ 0x2525, 0x2525, 0x2525, 0x0606, 0x1c17, 0x1709, 0x1c17, 0x1709, 0x0606, 0x0606, 0x0606, 0x0606, 0x3d3c, 0x3f3e, 0x4140, 0x1442,
+ 0x0707, 0x0707, 0x0607, 0x0606, 0x1706, 0x061c, 0x0606, 0x1206, 0x0612, 0x0606, 0x0943, 0x060a, 0x0606, 0x0606, 0x0606, 0x0606,
+ 0x0606, 0x060f, 0x0612, 0x0606, 0x0606, 0x0606, 0x0606, 0x0506, 0x1818, 0x1818, 0x0018, 0x4544, 0x4746, 0x1818, 0x1818, 0x1818,
+ 0x1f1b, 0x0000, 0x1b1b, 0x1b1b, 0x1b1b, 0x0b0b, 0x090f, 0x1f0a, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x0b0b, 0x090f, 0x000a,
+ 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x001f, 0x0000, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808,
+ 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0008, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2321, 0x2323,
+ 0x2123, 0x2323, 0x2123, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1510, 0x1515, 0x1015, 0x1515, 0x1013, 0x1010, 0x1313, 0x1010, 0x1310, 0x1015, 0x1515, 0x100f, 0x1010, 0x1010, 0x1515,
+ 0x1515, 0x1515, 0x1510, 0x1510, 0x1510, 0x1010, 0x1010, 0x1319, 0x1010, 0x1010, 0x1613, 0x1616, 0x1316, 0x1515, 0x1313, 0x1010,
+ 0x0f0f, 0x0f0f, 0x100f, 0x1313, 0x1313, 0x0f15, 0x1515, 0x2213, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d,
+ 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x1039, 0x3913, 0x3939, 0x1d39, 0x1515, 0x0000, 0x0000,
+ 0x0f0f, 0x0f0f, 0x150f, 0x1515, 0x1515, 0x0f0f, 0x1515, 0x1515, 0x150f, 0x0f15, 0x1515, 0x150f, 0x1515, 0x1515, 0x1515, 0x150f,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x1515, 0x150f, 0x150f, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
+ 0x0f0f, 0x1a0b, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x1515, 0x1515, 0x1515, 0x1515, 0x0a09, 0x0a09, 0x1515, 0x1515,
+ 0x0f0f, 0x1515, 0x1515, 0x1515, 0x0915, 0x150a, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1522, 0x150f, 0x1515,
+ 0x1515, 0x1515, 0x2215, 0x1515, 0x1515, 0x0f15, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x0f0f, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1d1d, 0x1d1d, 0x1d1d, 0x1515, 0x1515, 0x1515, 0x0f15, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x0f15, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f15, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1522, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d,
+ 0x1d1d, 0x1d1d, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x090f, 0x0f0a, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
+ 0x0f0f, 0x0f0f, 0x0f0f, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0f0f, 0x090f, 0x090a, 0x090a, 0x090a, 0x090a, 0x090a, 0x090a,
+ 0x090a, 0x090a, 0x090a, 0x090a, 0x0f0a, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0a09, 0x0a09, 0x0f0f, 0x0f0f,
+ 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0a09, 0x0f0f, 0x0f0f, 0x0f0f, 0x150f, 0x0f15, 0x0f0f, 0x0f0f, 0x150f, 0x1515,
+ 0x1515, 0x1515, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x0010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0013,
+ 0x1310, 0x1010, 0x1310, 0x1013, 0x1013, 0x1013, 0x1013, 0x1010, 0x1310, 0x1310, 0x1013, 0x1313, 0x1313, 0x1313, 0x1f1f, 0x1010,
+ 0x1310, 0x1310, 0x1513, 0x1515, 0x1515, 0x1015, 0x1013, 0x2113, 0x2121, 0x1310, 0x0000, 0x0000, 0x0600, 0x0606, 0x1d06, 0x0606,
+ 0x1313, 0x1313, 0x1313, 0x1300, 0x0000, 0x0000, 0x1300, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x1f00,
+ 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2100, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x0016, 0x0606, 0x1c17, 0x1c17, 0x0606, 0x1706, 0x061c, 0x1c17, 0x0606,
+ 0x0606, 0x0606, 0x0606, 0x2506, 0x0606, 0x0625, 0x1c17, 0x0606, 0x1c17, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0606, 0x0606, 0x2006,
+ 0x0606, 0x0606, 0x0606, 0x0606, 0x0606, 0x2525, 0x0606, 0x0606, 0x0625, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000,
+ 0x0605, 0x0606, 0x1f15, 0x3916, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x1515, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0925, 0x0a0a,
+ 0x3915, 0x3939, 0x3939, 0x3939, 0x3939, 0x2121, 0x2121, 0x3535, 0x1f25, 0x1f1f, 0x1f1f, 0x1515, 0x3939, 0x1f39, 0x0616, 0x1515,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x2100, 0x1121, 0x1f11, 0x161f, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0616, 0x1f1f, 0x161f,
+ 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2222, 0x3737, 0x3737, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1522, 0x0015,
+ 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x3737, 0x3737, 0x3737, 0x3737,
+ 0x1d15, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x2215,
+ 0x1d22, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x1515,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x2222, 0x2222, 0x2222, 0x1522, 0x1515, 0x2215, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1522,
+ 0x1616, 0x1616, 0x1f16, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x061f, 0x0606,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x0000, 0x0000, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x2116,
+ 0x2323, 0x0623, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2006, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1f1f, 0x2121,
+ 0x1616, 0x1616, 0x1616, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x2121, 0x2424, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1111, 0x1111, 0x1111, 0x2011, 0x2020, 0x2020, 0x2020, 0x2020, 0x1111, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310,
+ 0x1313, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x131f, 0x1313, 0x1313, 0x1313, 0x1013, 0x1013, 0x1013, 0x1310,
+ 0x1310, 0x1310, 0x1310, 0x1310, 0x4820, 0x1048, 0x1013, 0x1613, 0x1310, 0x1310, 0x1313, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310,
+ 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1010, 0x1010, 0x0000, 0x1010, 0x1010, 0x1310, 0x1310, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x1600, 0x1f1f, 0x1613, 0x1616, 0x1616, 0x1616, 0x1621, 0x1616, 0x1621, 0x1616, 0x2116, 0x1616, 0x1616,
+ 0x1616, 0x3516, 0x2135, 0x3521, 0x1515, 0x1515, 0x0000, 0x0000, 0x3737, 0x3737, 0x3737, 0x2222, 0x1908, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x0606, 0x0606, 0x0000, 0x0000, 0x0000, 0x0000, 0x3535, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x2424,
+ 0x2121, 0x1616, 0x1616, 0x1616, 0x2424, 0x1624, 0x1624, 0x0000, 0x1616, 0x1616, 0x1616, 0x2121, 0x2121, 0x2121, 0x2121, 0x2424,
+ 0x1616, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x3535, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2400,
+ 0x1616, 0x2116, 0x3535, 0x2121, 0x2121, 0x3535, 0x3521, 0x3535, 0x2435, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x1f00,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x0000, 0x2424, 0x1616, 0x1616, 0x2116, 0x161f, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x3521,
+ 0x2135, 0x3521, 0x2135, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x2116, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x2424, 0x2424, 0x161f, 0x1616, 0x1616, 0x2216, 0x2222, 0x3516, 0x3521, 0x1616,
+ 0x1621, 0x2121, 0x1621, 0x2116, 0x1621, 0x1616, 0x1616, 0x2121, 0x2116, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x1f16, 0x2424, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3516, 0x2121, 0x3535,
+ 0x2424, 0x1f16, 0x351f, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x0016, 0x1600, 0x1616, 0x1616, 0x0016,
+ 0x1600, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x4813, 0x1f1f, 0x1f1f,
+ 0x1313, 0x1313, 0x1313, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x3516, 0x2135, 0x3535, 0x3521, 0x2435, 0x2135, 0x0000,
+ 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x1600, 0x1616, 0x1616,
+ 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a,
+ 0x1313, 0x1313, 0x1313, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1300, 0x1313, 0x1313, 0x0000, 0x0000, 0x2800, 0x2821,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x0b28, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x2828, 0x2828, 0x0028, 0x0028,
+ 0x2828, 0x2800, 0x0028, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2e2e, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b,
+ 0x4b4b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x090a, 0x0000, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x0000, 0x0000, 0x0000, 0x0000, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x152b, 0x0000,
+ 0x0606, 0x0606, 0x0606, 0x0906, 0x060a, 0x0000, 0x0000, 0x0000, 0x2506, 0x1225, 0x0912, 0x090a, 0x090a, 0x090a, 0x090a, 0x090a,
+ 0x090a, 0x090a, 0x060a, 0x0906, 0x060a, 0x0606, 0x1206, 0x1212, 0x060c, 0x000c, 0x0c06, 0x0606, 0x0925, 0x090a, 0x090a, 0x070a,
+ 0x0606, 0x0d0b, 0x0f0f, 0x000f, 0x0806, 0x0607, 0x0000, 0x0000, 0x2e2e, 0x2e2e, 0x002e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x002e, 0x1800, 0x0600, 0x0706, 0x0708, 0x0606, 0x0a09, 0x0b06, 0x0d0c, 0x0c0c,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0913, 0x0a0f, 0x090f, 0x060a, 0x0a09, 0x0606, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x161f, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1f1f,
+ 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x0016, 0x0000,
+ 0x0808, 0x110f, 0x0815, 0x0008, 0x0f15, 0x0f0f, 0x150f, 0x0015, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c00, 0x4c4c, 0x1515, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1600,
+ 0x0624, 0x0024, 0x0000, 0x3700, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x0000, 0x2200, 0x2222, 0x2222, 0x2222, 0x2222, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d,
+ 0x4d4d, 0x4d4d, 0x1d4d, 0x1d1d, 0x151d, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1d1d, 0x0015, 0x0000,
+ 0x0015, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2122, 0x0000,
+ 0x1b21, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x0000, 0x0000,
+ 0x3737, 0x3737, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3916, 0x1616, 0x1616, 0x1616, 0x1616, 0x0039, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2400,
+ 0x1616, 0x1616, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x3924, 0x3939, 0x3939, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2400,
+ 0x2828, 0x2828, 0x2828, 0x0000, 0x0028, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2800, 0x0028, 0x0000, 0x0028, 0x2800,
+ 0x2828, 0x2828, 0x2828, 0x2700, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x4f28, 0x4e4f, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x0000, 0x0000, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2828, 0x0028, 0x2828, 0x0000, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x4e4e, 0x4e4e, 0x4e4e, 0x0000, 0x0600,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0000, 0x0000, 0x2700, 0x2828, 0x2828, 0x2828, 0x2828, 0x0000, 0x0000, 0x4e4e, 0x2828,
+ 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2128, 0x2121, 0x2100, 0x0021, 0x0000, 0x0000, 0x2121, 0x2121, 0x2828, 0x2828, 0x2800, 0x2828, 0x2800, 0x2828, 0x2828, 0x2828,
+ 0x2828, 0x2828, 0x0000, 0x0000, 0x2121, 0x0021, 0x0000, 0x2100, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2727, 0x2727, 0x2727, 0x2727, 0x0027, 0x0000, 0x0000, 0x0000, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x4e28, 0x274e,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x4e28, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x2828, 0x284f, 0x2828, 0x2828, 0x2828,
+ 0x2828, 0x2828, 0x2128, 0x0021, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x2727, 0x2727, 0x2727, 0x0027, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2828, 0x2828, 0x2828, 0x0000, 0x0600, 0x0606, 0x0606, 0x0606, 0x2828, 0x2828, 0x2828, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2828, 0x0028, 0x0000, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x2828, 0x0000, 0x0000, 0x0000, 0x2700, 0x2727, 0x0027, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x0000, 0x0000, 0x0000,
+ 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x0051, 0x0000, 0x0000, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x0052,
+ 0x2135, 0x1635, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2421, 0x2424, 0x2424, 0x2424, 0x0000, 0x0000, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d,
+ 0x1d1d, 0x1d1d, 0x1d1d, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2100,
+ 0x3535, 0x2135, 0x2121, 0x3521, 0x2135, 0x2421, 0x3a24, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x2121, 0x1621, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x2135, 0x2121, 0x2121, 0x2121, 0x0021, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636,
+ 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x2116, 0x2424, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x3516, 0x3535, 0x2121, 0x2121, 0x2121, 0x2121, 0x3521, 0x1635, 0x1616, 0x2416, 0x2424, 0x2424, 0x2121, 0x2421, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2416, 0x2416, 0x2424, 0x3700, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x0037, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3535, 0x2135,
+ 0x2121, 0x3535, 0x3521, 0x2121, 0x2424, 0x2424, 0x2424, 0x0000, 0x1616, 0x1616, 0x1616, 0x0016, 0x0016, 0x1616, 0x1616, 0x1600,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x3535, 0x2135, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000,
+ 0x2121, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x3521, 0x3535, 0x0035, 0x3500, 0x0035, 0x3500, 0x3535, 0x0000,
+ 0x0016, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x3535, 0x0000, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000,
+ 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3535, 0x2135, 0x2121, 0x2121, 0x3521, 0x3521, 0x3535, 0x2135,
+ 0x3521, 0x2121, 0x1616, 0x1624, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3516,
+ 0x3535, 0x2121, 0x2121, 0x0000, 0x3535, 0x3535, 0x2121, 0x2135, 0x2421, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424,
+ 0x2424, 0x2424, 0x2424, 0x2424, 0x1616, 0x1616, 0x2121, 0x0000, 0x3535, 0x2135, 0x2121, 0x2121, 0x2121, 0x3521, 0x2135, 0x2135,
+ 0x2421, 0x2424, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x2135, 0x3535,
+ 0x2121, 0x2121, 0x2121, 0x2135, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x2100, 0x2121,
+ 0x3535, 0x2121, 0x2121, 0x2135, 0x2121, 0x2121, 0x0000, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3737, 0x2424, 0x2224,
+ 0x3737, 0x0037, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x0039,
+ 0x2424, 0x2424, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2121, 0x2121, 0x2421, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2121, 0x2121, 0x2121, 0x2421, 0x2424, 0x2424, 0x2222, 0x2222, 0x1f1f, 0x1f1f, 0x2224, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3700, 0x3737, 0x3737, 0x3737, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x1600, 0x1616, 0x3516, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535,
+ 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x0035,
+ 0x2121, 0x1f21, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x2122, 0x2421, 0x1818, 0x1818, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2222, 0x2222, 0x2222, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x0022, 0x2200, 0x2222, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x3522, 0x2135, 0x2121, 0x2222, 0x3522, 0x3535, 0x3535, 0x1835, 0x1818, 0x1818, 0x1818, 0x2118, 0x2121, 0x2121,
+ 0x2121, 0x2221, 0x2122, 0x2121, 0x2121, 0x2121, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2121, 0x2121, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x0000, 0x0000, 0x1515, 0x2121, 0x1521, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3737, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1313,
+ 0x1313, 0x1313, 0x0013, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0010, 0x1010, 0x0000, 0x0010, 0x1000, 0x0010, 0x1000, 0x1010, 0x0010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1300, 0x1300, 0x1313, 0x1313, 0x1313, 0x1300, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1010, 0x1000, 0x1010, 0x0010, 0x1000, 0x1010, 0x1010, 0x1010, 0x0010, 0x1010, 0x1010, 0x1010, 0x0010, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1000, 0x1010, 0x0010, 0x1010, 0x1010, 0x0010, 0x0010, 0x0000, 0x1010, 0x1010, 0x1010,
+ 0x0010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0000, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313,
+ 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1310, 0x0000, 0x0e0e,
+ 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x2121, 0x2121, 0x2121, 0x2221, 0x2222, 0x2122, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2221, 0x2222, 0x2222, 0x2222, 0x2122, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2221, 0x2422, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2100, 0x2121, 0x2121,
+ 0x2828, 0x2828, 0x0028, 0x4e00, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e00, 0x002e, 0x002e, 0x2e00, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x002e, 0x2e2e, 0x2e2e, 0x2e00, 0x2e00, 0x0000, 0x0000, 0x0000, 0x002e, 0x0000, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x2e2e,
+ 0x2e00, 0x002e, 0x002e, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x002e, 0x002e, 0x2e00, 0x2e2e, 0x002e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x002e, 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x002e, 0x002e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x0000, 0x0000, 0x2e00, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e,
+ 0x0f0f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015,
+ 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1d1b, 0x001d, 0x0000,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2222, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1115, 0x1111, 0x1111,
+ 0x1515, 0x1515, 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000,
+ 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x0000,
+ 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818,
+ 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x0000, 0xeeee, 0xeeee
+ };
+
+ private static byte[] s_pCategoriesValue = new byte[]
+ {
+ 0x1d, 0x00, 0x0e, 0x0e, 0x0e, 0x10, 0x0e, 0x0f, 0x0e, 0x11, 0x0b, 0x11, 0x18, 0x12, 0x18, 0x0a,
+ 0x1a, 0x0a, 0x14, 0x12, 0x15, 0x12, 0x19, 0x09, 0x18, 0x0c, 0x13, 0x09, 0x08, 0x08, 0x19, 0x12,
+ 0x00, 0x00, 0x1b, 0x12, 0x12, 0x12, 0x01, 0x00, 0x0b, 0x0c, 0x1c, 0x12, 0x04, 0x00, 0x16, 0x12,
+ 0x0f, 0x0e, 0x1c, 0x0a, 0x19, 0x0a, 0x0a, 0x08, 0x17, 0x12, 0x0a, 0x12, 0x02, 0x00, 0x03, 0x00,
+ 0x03, 0x12, 0x05, 0x0d, 0x1c, 0x00, 0x07, 0x0d, 0x18, 0x00, 0x13, 0x12, 0x13, 0x03, 0x18, 0x03,
+ 0x04, 0x03, 0x0f, 0x0b, 0x19, 0x04, 0x1a, 0x04, 0x18, 0x04, 0x0f, 0x04, 0x04, 0x04, 0x03, 0x04,
+ 0x08, 0x0b, 0x18, 0x0b, 0x1c, 0x04, 0x08, 0x03, 0x03, 0x03, 0x06, 0x00, 0x08, 0x00, 0x0a, 0x00,
+ 0x05, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x0f, 0x03, 0x0c, 0x11, 0x0d, 0x0f, 0x0f, 0x01, 0x0f, 0x05,
+ 0x0f, 0x07, 0x0f, 0x02, 0x0f, 0x06, 0x19, 0x0c, 0x0f, 0x13, 0x0f, 0x14, 0x0f, 0x15, 0x0f, 0x16,
+ 0x1b, 0x00, 0x10, 0x00, 0x11, 0x00, 0x1b, 0x04, 0x0f, 0x12, 0x09, 0x12, 0x0a, 0x03, 0x1c, 0x03,
+ 0x00, 0x03, 0x01, 0x03, 0x0a, 0x0b, 0x19, 0x00
+ };
+ // 12:4:4 index table of the Unicode numeric data.
+ private static ushort[] s_pNumericLevel1Index = new ushort[]
+ {
+ 0x1100, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1120, 0x1130, 0x1110, 0x1140, 0x1150, 0x1160, 0x1170, 0x1180, 0x1190, 0x11a0,
+ 0x11b0, 0x1110, 0x1110, 0x11c0, 0x1110, 0x1110, 0x11d0, 0x11e0, 0x11f0, 0x1200, 0x1210, 0x1220, 0x1230, 0x1110, 0x1110, 0x1110,
+ 0x1240, 0x1250, 0x1110, 0x1110, 0x1260, 0x1110, 0x1110, 0x1270, 0x1110, 0x1110, 0x1110, 0x1110, 0x1280, 0x1110, 0x1110, 0x1110,
+ 0x1290, 0x12a0, 0x12b0, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x12c0, 0x1110, 0x12d0, 0x12e0, 0x12f0, 0x1300, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1310, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x11f0,
+ 0x1110, 0x1320, 0x1330, 0x1340, 0x1350, 0x1110, 0x1110, 0x1110, 0x1360, 0x1370, 0x1380, 0x1390, 0x13a0, 0x1110, 0x13b0, 0x1110,
+ 0x13c0, 0x13d0, 0x1300, 0x1110, 0x13e0, 0x1110, 0x13f0, 0x1400, 0x1410, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1420, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1430, 0x1440, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1450, 0x1110, 0x1110, 0x1110, 0x1460, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1470, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1480, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1490, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14c0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14c8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14d0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14d8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14e0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14e8, 0x14f0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14f8, 0x1500, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1508, 0x1510,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x1518,
+ 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1520, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1528, 0x1530, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1538, 0x1540, 0x1540, 0x1548, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1550, 0x1558, 0x1560, 0x1568, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1570, 0x1578,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1580, 0x1588, 0x1590, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1598,
+ 0x15a0, 0x14a0, 0x15a8, 0x15b0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x15b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x15c0, 0x14a0, 0x15c8, 0x15d0, 0x14a0, 0x14a0, 0x15c0, 0x14a0, 0x14a0, 0x15d8, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x15e0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x15e8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0,
+ 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x15f0, 0x15f8, 0x14a0, 0x14a0, 0x14a0, 0x1600, 0x14a0, 0x1608, 0x14a0, 0x1610,
+ 0x1618, 0x1620, 0x1628, 0x1630, 0x1638, 0x1640, 0x1648, 0x1650, 0x1658, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1660, 0x1668,
+ 0x14a0, 0x14a0, 0x1670, 0x14a0, 0x1678, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1680, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1688, 0x14a0, 0x1690, 0x14a0, 0x14a0, 0x1698, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16a0,
+ 0x14a0, 0x16a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16b0, 0x16b8, 0x16c0, 0x16c8, 0x16d0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16d8, 0x14a0, 0x14a0, 0x16e0, 0x14a0, 0x16e8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16f0, 0x14a0, 0x16f0, 0x14a0, 0x14a0, 0x16f8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1700,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1708, 0x1710, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1718, 0x1720, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x1660, 0x1728,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x1730, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1738, 0x1740,
+ 0x1748, 0x1750, 0x1758, 0x1760, 0x1768, 0x1770, 0x1778, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1780, 0x1788, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16b8, 0x1790, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1798, 0x17a0, 0x17a8, 0x17b0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1618, 0x14a0, 0x14a0, 0x14a0,
+ 0x17b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x17c0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0c0b, 0x0000, 0x0000, 0x0d00, 0x0000, 0x0f0e, 0x0010, 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09,
+ 0x0000, 0x0000, 0x1211, 0x0e13, 0x1410, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f0e, 0x1110, 0x1312, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1615, 0x0017, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1918, 0x1b1a, 0x1a19, 0x001b,
+ 0x1615, 0x0e17, 0x100f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x1c0f, 0x1e1d, 0x201f,
+ 0x2221, 0x2423, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0d00, 0x0c0b, 0x2625, 0x2827,
+ 0x2a29, 0x2b15, 0x2d2c, 0x2f2e, 0x3130, 0x1632, 0x0033, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3534,
+ 0x0036, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1918, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x0000, 0x0000, 0x0000,
+ 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x000d, 0x0000, 0x0000, 0x003d, 0x0000, 0x2625, 0x2827, 0x2a29, 0x0000, 0x0000, 0x0000,
+ 0x0d3d, 0x0c0b, 0x2625, 0x2827, 0x2a29, 0x0000, 0x0000, 0x0000, 0x3f3e, 0x4140, 0x4342, 0x4544, 0x4746, 0x1248, 0x4a49, 0x194b,
+ 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x153c, 0x4d4c, 0x162e, 0x174e, 0x4f17, 0x0033, 0x3900, 0x502e, 0x1851, 0x0000, 0x0000, 0x0000,
+ 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x4d4c, 0x5352, 0x1454, 0x3534, 0x2b36, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x4d4c,
+ 0x5352, 0x1454, 0x3534, 0x2b36, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x4d4c, 0x5352, 0x1454, 0x3534, 0x2b36, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c3d, 0x524d, 0x5453, 0x3414, 0x3635, 0x0d2b, 0x0c0b, 0x2625, 0x2827, 0x2a29, 0x3d15,
+ 0x0000, 0x0000, 0x0000, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x0b0d, 0x250c, 0x2726,
+ 0x2928, 0x152a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f00, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2b15, 0x002c, 0x0000, 0x0000, 0x0000, 0x1a19, 0x371b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x153c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b15, 0x2d2c, 0x2f2e, 0x3130,
+ 0x5500, 0x5756, 0x5958, 0x5b5a, 0x5d5c, 0x5e2c, 0x605f, 0x6261, 0x6300, 0x6564, 0x2d66, 0x6867, 0x6a69, 0x6c6b, 0x6e6d, 0x2e6f,
+ 0x0000, 0x0000, 0x0000, 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x183c, 0x0f0e, 0x1110, 0x1312, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1b00, 0x0000, 0x0000, 0x0000, 0x1500, 0x0000, 0x0000, 0x001a, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0018, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3900, 0x3900, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1500, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3837, 0x3a39, 0x3c3b,
+ 0x2b15, 0x2d2c, 0x2f2e, 0x3130, 0x1632, 0x7170, 0x4e72, 0x7473, 0x7675, 0x7717, 0x7978, 0x7a4f, 0x7c7b, 0x337d, 0x7f7e, 0x5080,
+ 0x8281, 0x8483, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f0e, 0x3819, 0x4e2e, 0x504f, 0x1538, 0x162e, 0x174e, 0x384f,
+ 0x2e15, 0x4e16, 0x3317, 0x1550, 0x1919, 0x1a19, 0x1a1a, 0x381a, 0x1515, 0x1515, 0x2c15, 0x2e2e, 0x2e2e, 0x7116, 0x4e4e, 0x4e4e,
+ 0x174e, 0x384f, 0x0f2e, 0x420f, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e18, 0x0000, 0x0000,
+ 0x1900, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x2b15, 0x2d2c, 0x2f2e, 0x3130, 0x1632, 0x7170, 0x4e72, 0x7473, 0x7675, 0x0000, 0x0000,
+ 0x3819, 0x2e15, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3200, 0x0000, 0x0000, 0x0000, 0x0000, 0x0076, 0x0000, 0x0000,
+ 0x1900, 0x151a, 0x162b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1a19, 0x151b, 0x162b, 0x3317,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3837, 0x2b15, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3737, 0x1538, 0x162b,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1538, 0x162b, 0x0000, 0x0000, 0x0000, 0x1519, 0x162b, 0x1b1a, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f85, 0x0000, 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x153c, 0x2c2b, 0x2e2d, 0x302f,
+ 0x0000, 0x7016, 0x7271, 0x734e, 0x7574, 0x1776, 0x7877, 0x4f79, 0x7b7a, 0x7d7c, 0x7e33, 0x807f, 0x8150, 0x8382, 0x5184, 0x8786,
+ 0x8988, 0x8b8a, 0x8d8c, 0x8f8e, 0x9190, 0x9392, 0x9594, 0x9796, 0x0b0d, 0x250c, 0x2b15, 0x1716, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x002e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x2b15,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1a19, 0x371b, 0x2b15, 0x1716, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x1537, 0x162b,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3819, 0x2e15, 0x1716, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x2c2b, 0x2e2d, 0x302f,
+ 0x3231, 0x7016, 0x7271, 0x734e, 0x7574, 0x0f76, 0x410e, 0x0042, 0x0000, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x2c2b, 0x2e2d,
+ 0x302f, 0x3231, 0x1716, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x3130, 0x1632, 0x0017, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x2b15, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x2b15, 0x2d2c, 0x2f2e,
+ 0x3130, 0x0032, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x371b, 0x3938, 0x3b3a, 0x373c,
+ 0x3938, 0x3b3a, 0x193c, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x1a19, 0x371b, 0x1a38, 0x1b1b, 0x3837, 0x3a39, 0x3c3b, 0x1a19, 0x1b1b,
+ 0x3837, 0x9998, 0x1a19, 0x1b1b, 0x3837, 0x1b1b, 0x3737, 0x3737, 0x3a39, 0x3a3a, 0x3b3b, 0x3c3c, 0x3c3c, 0x1b1a, 0x3837, 0x1939,
+ 0x1b1a, 0x3737, 0x3838, 0x1b1a, 0x1a19, 0x4241, 0x4148, 0x1242, 0x470e, 0x0e0e, 0x410f, 0x2d42, 0x372e, 0x3938, 0x3b3a, 0x003c,
+ 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x1500, 0x3316, 0x9b9a, 0x9d9c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3231, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0201,
+ 0x0403, 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403,
+ 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x3d3d, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x182a, 0x0018, 0x0000,
+ 0x003c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xeeee, 0xeeee, 0xeeee, 0xeeee
+ };
+ // Every item contains the value for numeric value.
+ private static byte[] s_pNumericValues = new byte[]
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8f, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x51, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x56, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xc3, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x92, 0x24, 0x49, 0x92, 0x24, 0x49, 0xc2, 0x3f, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, 0xbc, 0x3f,
+ 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xb9, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xe5, 0x3f, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xc9, 0x3f,
+ 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xd9, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xe3, 0x3f,
+ 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe9, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xc5, 0x3f,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xb3, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe8, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xf8, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x45, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x46, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x47, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x82, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x8c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x9f, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xa7, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xaf, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xb7, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xbb, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0xc1, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xd3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xdd, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xed, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0xf5, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xed, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x12, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x18, 0x41, 0x00, 0x00, 0x00, 0x00, 0x80, 0x84, 0x1e, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x5c, 0x25, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x28, 0x41, 0x00, 0x00, 0x00, 0x00, 0x40, 0x77, 0x2b, 0x41,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xb5, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xc5, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xda, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xe2, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xe5, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x0a, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x1a, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x84, 0x2e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x84, 0xd7, 0x97, 0x41,
+ 0x00, 0x00, 0x00, 0x20, 0x5f, 0xa0, 0x02, 0x42, 0x00, 0x00, 0x00, 0xa2, 0x94, 0x1a, 0x6d, 0x42
+ };
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs b/src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs
new file mode 100644
index 0000000000..48f62019d7
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs
@@ -0,0 +1,399 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about ChineseLunisolarCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1901/02/19 2101/01/28
+ ** ChineseLunisolar 1901/01/01 2100/12/29
+ */
+ [Serializable]
+ public class ChineseLunisolarCalendar : EastAsianLunisolarCalendar
+ {
+ //
+ // The era value for the current era.
+ //
+
+ public const int ChineseEra = 1;
+
+ internal const int MIN_LUNISOLAR_YEAR = 1901;
+ internal const int MAX_LUNISOLAR_YEAR = 2100;
+
+ internal const int MIN_GREGORIAN_YEAR = 1901;
+ internal const int MIN_GREGORIAN_MONTH = 2;
+ internal const int MIN_GREGORIAN_DAY = 19;
+
+ internal const int MAX_GREGORIAN_YEAR = 2101;
+ internal const int MAX_GREGORIAN_MONTH = 1;
+ internal const int MAX_GREGORIAN_DAY = 28;
+
+ internal static DateTime minDate = new DateTime(MIN_GREGORIAN_YEAR, MIN_GREGORIAN_MONTH, MIN_GREGORIAN_DAY);
+ internal static DateTime maxDate = new DateTime((new DateTime(MAX_GREGORIAN_YEAR, MAX_GREGORIAN_MONTH, MAX_GREGORIAN_DAY, 23, 59, 59, 999)).Ticks + 9999);
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // 1900: 1-29 2-30 3-29 4-29 5-30 6-29 7-30 8-30 Leap8-29 9-30 10-30 11-29 12-30 from Calendrical Tabulations
+ return 384;
+ }
+ }
+
+
+ private static readonly int[,] s_yinfo =
+ {
+ /*Y LM Lmon Lday DaysPerMonth D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 #Days
+ 1901 */
+ { 0 , 2 , 19 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1902 */{ 0 , 2 , 8 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1903 */{ 5 , 1 , 29 , 21096 },/* 29 30 29 30 29 29 30 29 29 30 30 29 30 383
+1904 */{ 0 , 2 , 16 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1905 */{ 0 , 2 , 4 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1906 */{ 4 , 1 , 25 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1907 */{ 0 , 2 , 13 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1908 */{ 0 , 2 , 2 , 39632 },/* 30 29 29 30 30 29 30 29 30 30 29 30 0 355
+1909 */{ 2 , 1 , 22 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1910 */{ 0 , 2 , 10 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1911 */{ 6 , 1 , 30 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1912 */{ 0 , 2 , 18 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1913 */{ 0 , 2 , 6 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1914 */{ 5 , 1 , 26 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1915 */{ 0 , 2 , 14 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1916 */{ 0 , 2 , 3 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 0 355
+1917 */{ 2 , 1 , 23 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1918 */{ 0 , 2 , 11 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1919 */{ 7 , 2 , 1 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1920 */{ 0 , 2 , 20 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1921 */{ 0 , 2 , 8 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1922 */{ 5 , 1 , 28 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1923 */{ 0 , 2 , 16 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1924 */{ 0 , 2 , 5 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1925 */{ 4 , 1 , 24 , 44456 },/* 30 29 30 29 30 30 29 30 30 29 30 29 30 385
+1926 */{ 0 , 2 , 13 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1927 */{ 0 , 2 , 2 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1928 */{ 2 , 1 , 23 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1929 */{ 0 , 2 , 10 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1930 */{ 6 , 1 , 30 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1931 */{ 0 , 2 , 17 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1932 */{ 0 , 2 , 6 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1933 */{ 5 , 1 , 26 , 27976 },/* 29 30 30 29 30 30 29 30 29 30 29 29 30 384
+1934 */{ 0 , 2 , 14 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1935 */{ 0 , 2 , 4 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1936 */{ 3 , 1 , 24 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1937 */{ 0 , 2 , 11 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1938 */{ 7 , 1 , 31 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1939 */{ 0 , 2 , 19 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1940 */{ 0 , 2 , 8 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1941 */{ 6 , 1 , 27 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1942 */{ 0 , 2 , 15 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1943 */{ 0 , 2 , 5 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1944 */{ 4 , 1 , 25 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+1945 */{ 0 , 2 , 13 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1946 */{ 0 , 2 , 2 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+1947 */{ 2 , 1 , 22 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+1948 */{ 0 , 2 , 10 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1949 */{ 7 , 1 , 29 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+1950 */{ 0 , 2 , 17 , 27808 },/* 29 30 30 29 30 30 29 29 30 29 30 29 0 354
+1951 */{ 0 , 2 , 6 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1952 */{ 5 , 1 , 27 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+1953 */{ 0 , 2 , 14 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1954 */{ 0 , 2 , 3 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+1955 */{ 3 , 1 , 24 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1956 */{ 0 , 2 , 12 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1957 */{ 8 , 1 , 31 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 29 383
+1958 */{ 0 , 2 , 18 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+1959 */{ 0 , 2 , 8 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1960 */{ 6 , 1 , 28 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1961 */{ 0 , 2 , 15 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1962 */{ 0 , 2 , 5 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1963 */{ 4 , 1 , 25 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1964 */{ 0 , 2 , 13 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1965 */{ 0 , 2 , 2 , 21088 },/* 29 30 29 30 29 29 30 29 29 30 30 29 0 353
+1966 */{ 3 , 1 , 21 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1967 */{ 0 , 2 , 9 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1968 */{ 7 , 1 , 30 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1969 */{ 0 , 2 , 17 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1970 */{ 0 , 2 , 6 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1971 */{ 5 , 1 , 27 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1972 */{ 0 , 2 , 15 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+1973 */{ 0 , 2 , 3 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1974 */{ 4 , 1 , 23 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1975 */{ 0 , 2 , 11 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1976 */{ 8 , 1 , 31 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1977 */{ 0 , 2 , 18 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1978 */{ 0 , 2 , 7 , 46752 },/* 30 29 30 30 29 30 30 29 30 29 30 29 0 355
+1979 */{ 6 , 1 , 28 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1980 */{ 0 , 2 , 16 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1981 */{ 0 , 2 , 5 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1982 */{ 4 , 1 , 25 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1983 */{ 0 , 2 , 13 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1984 */{ 10 , 2 , 2 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1985 */{ 0 , 2 , 20 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1986 */{ 0 , 2 , 9 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1987 */{ 6 , 1 , 29 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 29 384
+1988 */{ 0 , 2 , 17 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1989 */{ 0 , 2 , 6 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1990 */{ 5 , 1 , 27 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1991 */{ 0 , 2 , 15 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1992 */{ 0 , 2 , 4 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1993 */{ 3 , 1 , 23 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1994 */{ 0 , 2 , 10 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1995 */{ 8 , 1 , 31 , 27432 },/* 29 30 30 29 30 29 30 30 29 29 30 29 30 384
+1996 */{ 0 , 2 , 19 , 23232 },/* 29 30 29 30 30 29 30 29 30 30 29 29 0 354
+1997 */{ 0 , 2 , 7 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1998 */{ 5 , 1 , 28 , 37736 },/* 30 29 29 30 29 29 30 30 29 30 30 29 30 384
+1999 */{ 0 , 2 , 16 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2000 */{ 0 , 2 , 5 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2001 */{ 4 , 1 , 24 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+2002 */{ 0 , 2 , 12 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2003 */{ 0 , 2 , 1 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2004 */{ 2 , 1 , 22 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2005 */{ 0 , 2 , 9 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+2006 */{ 7 , 1 , 29 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+2007 */{ 0 , 2 , 18 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+2008 */{ 0 , 2 , 7 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+2009 */{ 5 , 1 , 26 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+2010 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2011 */{ 0 , 2 , 3 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2012 */{ 4 , 1 , 23 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+2013 */{ 0 , 2 , 10 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2014 */{ 9 , 1 , 31 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2015 */{ 0 , 2 , 19 , 19360 },/* 29 30 29 29 30 29 30 30 30 29 30 29 0 354
+2016 */{ 0 , 2 , 8 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2017 */{ 6 , 1 , 28 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+2018 */{ 0 , 2 , 16 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2019 */{ 0 , 2 , 5 , 43312 },/* 30 29 30 29 30 29 29 30 29 29 30 30 0 354
+2020 */{ 4 , 1 , 25 , 29864 },/* 29 30 30 30 29 30 29 29 30 29 30 29 30 384
+2021 */{ 0 , 2 , 12 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2022 */{ 0 , 2 , 1 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2023 */{ 2 , 1 , 22 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+2024 */{ 0 , 2 , 10 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2025 */{ 6 , 1 , 29 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+2026 */{ 0 , 2 , 17 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+2027 */{ 0 , 2 , 6 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+2028 */{ 5 , 1 , 26 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+2029 */{ 0 , 2 , 13 , 54576 },/* 30 30 29 30 29 30 29 30 29 29 30 30 0 355
+2030 */{ 0 , 2 , 3 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+2031 */{ 3 , 1 , 23 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+2032 */{ 0 , 2 , 11 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2033 */{ 11 , 1 , 31 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+2034 */{ 0 , 2 , 19 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+2035 */{ 0 , 2 , 8 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2036 */{ 6 , 1 , 28 , 53848 },/* 30 30 29 30 29 29 30 29 29 30 29 30 30 384
+2037 */{ 0 , 2 , 15 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+2038 */{ 0 , 2 , 4 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2039 */{ 5 , 1 , 24 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 29 384
+2040 */{ 0 , 2 , 12 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+2041 */{ 0 , 2 , 1 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+2042 */{ 2 , 1 , 22 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+2043 */{ 0 , 2 , 10 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+2044 */{ 7 , 1 , 30 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+2045 */{ 0 , 2 , 17 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+2046 */{ 0 , 2 , 6 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+2047 */{ 5 , 1 , 26 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+2048 */{ 0 , 2 , 14 , 27936 },/* 29 30 30 29 30 30 29 30 29 29 30 29 0 354
+2049 */{ 0 , 2 , 2 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+2050 */{ 3 , 1 , 23 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+2051 */{ 0 , 2 , 11 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+2052 */{ 8 , 2 , 1 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+2053 */{ 0 , 2 , 19 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+2054 */{ 0 , 2 , 8 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+2055 */{ 6 , 1 , 28 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+2056 */{ 0 , 2 , 15 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+2057 */{ 0 , 2 , 4 , 27424 },/* 29 30 30 29 30 29 30 30 29 29 30 29 0 354
+2058 */{ 4 , 1 , 24 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 29 384
+2059 */{ 0 , 2 , 12 , 43744 },/* 30 29 30 29 30 29 30 29 30 30 30 29 0 355
+2060 */{ 0 , 2 , 2 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2061 */{ 3 , 1 , 21 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 29 384
+2062 */{ 0 , 2 , 9 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2063 */{ 7 , 1 , 29 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+2064 */{ 0 , 2 , 17 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2065 */{ 0 , 2 , 5 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2066 */{ 5 , 1 , 26 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2067 */{ 0 , 2 , 14 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+2068 */{ 0 , 2 , 3 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+2069 */{ 4 , 1 , 23 , 21224 },/* 29 30 29 30 29 29 30 29 30 30 30 29 30 384
+2070 */{ 0 , 2 , 11 , 21200 },/* 29 30 29 30 29 29 30 29 30 30 29 30 0 354
+2071 */{ 8 , 1 , 31 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+2072 */{ 0 , 2 , 19 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2073 */{ 0 , 2 , 7 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2074 */{ 6 , 1 , 27 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+2075 */{ 0 , 2 , 15 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2076 */{ 0 , 2 , 5 , 21920 },/* 29 30 29 30 29 30 29 30 30 29 30 29 0 354
+2077 */{ 4 , 1 , 24 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 29 384
+2078 */{ 0 , 2 , 12 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2079 */{ 0 , 2 , 2 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2080 */{ 3 , 1 , 22 , 43320 },/* 30 29 30 29 30 29 29 30 29 29 30 30 30 384
+2081 */{ 0 , 2 , 9 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 0 354
+2082 */{ 7 , 1 , 29 , 29336 },/* 29 30 30 30 29 29 30 29 30 29 29 30 30 384
+2083 */{ 0 , 2 , 17 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2084 */{ 0 , 2 , 6 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2085 */{ 5 , 1 , 26 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+2086 */{ 0 , 2 , 14 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2087 */{ 0 , 2 , 3 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+2088 */{ 4 , 1 , 24 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 29 383
+2089 */{ 0 , 2 , 10 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+2090 */{ 8 , 1 , 30 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+2091 */{ 0 , 2 , 18 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2092 */{ 0 , 2 , 7 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+2093 */{ 6 , 1 , 27 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+2094 */{ 0 , 2 , 15 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+2095 */{ 0 , 2 , 5 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+2096 */{ 4 , 1 , 25 , 42216 },/* 30 29 30 29 29 30 29 29 30 30 30 29 30 384
+2097 */{ 0 , 2 , 12 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2098 */{ 0 , 2 , 1 , 53584 },/* 30 30 29 30 29 29 29 30 29 30 29 30 0 354
+2099 */{ 2 , 1 , 21 , 55592 },/* 30 30 29 30 30 29 29 30 29 29 30 29 30 384
+2100 */{ 0 , 2 , 9 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+ */};
+
+
+ internal override int MinCalendarYear
+ {
+ get
+ {
+ return (MIN_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override int MaxCalendarYear
+ {
+ get
+ {
+ return (MAX_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override DateTime MinDate
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ internal override DateTime MaxDate
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ internal override EraInfo[] CalEraInfo
+ {
+ get
+ {
+ return (null);
+ }
+ }
+
+ internal override int GetYearInfo(int LunarYear, int Index)
+ {
+ if ((LunarYear < MIN_LUNISOLAR_YEAR) || (LunarYear > MAX_LUNISOLAR_YEAR))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, MIN_LUNISOLAR_YEAR, MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return s_yinfo[LunarYear - MIN_LUNISOLAR_YEAR, Index];
+ }
+
+ internal override int GetYear(int year, DateTime time)
+ {
+ return year;
+ }
+
+ internal override int GetGregorianYear(int year, int era)
+ {
+ if (era != CurrentEra && era != ChineseEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ if (year < MIN_LUNISOLAR_YEAR || year > MAX_LUNISOLAR_YEAR)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, MIN_LUNISOLAR_YEAR, MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return year;
+ }
+
+ public ChineseLunisolarCalendar()
+ {
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetEra(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return (ChineseEra);
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.CHINESELUNISOLAR);
+ }
+ }
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ //Use CAL_GREGORIAN just to get CurrentEraValue as 1 since we do not have data under the ID CAL_ChineseLunisolar yet
+ return (CalendarId.GREGORIAN);
+ }
+ }
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { ChineseEra });
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs
new file mode 100644
index 0000000000..2aaf5a22fa
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs
@@ -0,0 +1,315 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace System.Globalization
+{
+ public partial class CompareInfo
+ {
+ [NonSerialized]
+ private Interop.GlobalizationInterop.SafeSortHandle _sortHandle;
+
+ [NonSerialized]
+ private bool _isAsciiEqualityOrdinal;
+
+ [SecuritySafeCritical]
+ internal CompareInfo(CultureInfo culture)
+ {
+ _name = culture.m_name;
+ InitSort(culture);
+ }
+
+ private void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+ _sortHandle = Interop.GlobalizationInterop.GetSortHandle(GetNullTerminatedUtf8String(_sortName));
+ _isAsciiEqualityOrdinal = (_sortName == "en-US" || _sortName == "");
+ }
+
+ internal static unsafe int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ if (value.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (count < value.Length)
+ {
+ return -1;
+ }
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = source)
+ {
+ int index = Interop.GlobalizationInterop.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + startIndex, count, findLast: false);
+ return index != -1 ?
+ startIndex + index :
+ -1;
+ }
+ }
+
+ int endIndex = startIndex + (count - value.Length);
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++) ;
+
+ if (valueIndex == value.Length)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal static unsafe int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ if (value.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (count < value.Length)
+ {
+ return -1;
+ }
+
+ // startIndex is the index into source where we start search backwards from.
+ // leftStartIndex is the index into source of the start of the string that is
+ // count characters away from startIndex.
+ int leftStartIndex = startIndex - count + 1;
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = source)
+ {
+ int lastIndex = Interop.GlobalizationInterop.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true);
+ return lastIndex != -1 ?
+ leftStartIndex + lastIndex :
+ -1;
+ }
+ }
+
+ for (int i = startIndex - value.Length + 1; i >= leftStartIndex; i--)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++) ;
+
+ if (valueIndex == value.Length) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ private int GetHashCodeOfStringCore(string source, CompareOptions options)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return GetHashCodeOfStringCore(source, options, forceRandomizedHashing: false, additionalEntropy: 0);
+ }
+
+ private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
+ {
+ return Interop.GlobalizationInterop.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2);
+ }
+
+ private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
+ {
+ Contract.Assert(string1 != null);
+ Contract.Assert(string2 != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ fixed (char* pString1 = string1)
+ {
+ fixed (char* pString2 = string2)
+ {
+ return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1 + offset1, length1, pString2 + offset2, length2, options);
+ }
+ }
+ }
+
+ private unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return IndexOfOrdinal(source, target, startIndex, count, ignoreCase: false);
+ }
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && target.IsFastSort())
+ {
+ return IndexOf(source, target, startIndex, count, GetOrdinalCompareOptions(options));
+ }
+
+ fixed (char* pSource = source)
+ {
+ int index = Interop.GlobalizationInterop.IndexOf(_sortHandle, target, target.Length, pSource + startIndex, count, options);
+
+ return index != -1 ? index + startIndex : -1;
+ }
+ }
+
+ private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return LastIndexOfOrdinal(source, target, startIndex, count, ignoreCase: false);
+ }
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && target.IsFastSort())
+ {
+ return LastIndexOf(source, target, startIndex, count, GetOrdinalCompareOptions(options));
+ }
+
+ // startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source
+ // of the start of the string that is count characters away from startIndex.
+ int leftStartIndex = (startIndex - count + 1);
+
+ fixed (char* pSource = source)
+ {
+ int lastIndex = Interop.GlobalizationInterop.LastIndexOf(_sortHandle, target, target.Length, pSource + (startIndex - count + 1), count, options);
+
+ return lastIndex != -1 ? lastIndex + leftStartIndex : -1;
+ }
+ }
+
+ [SecuritySafeCritical]
+ private bool StartsWith(string source, string prefix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(prefix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && prefix.IsFastSort())
+ {
+ return IsPrefix(source, prefix, GetOrdinalCompareOptions(options));
+ }
+
+ return Interop.GlobalizationInterop.StartsWith(_sortHandle, prefix, prefix.Length, source, source.Length, options);
+ }
+
+ [SecuritySafeCritical]
+ private bool EndsWith(string source, string suffix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(suffix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && suffix.IsFastSort())
+ {
+ return IsSuffix(source, suffix, GetOrdinalCompareOptions(options));
+ }
+
+ return Interop.GlobalizationInterop.EndsWith(_sortHandle, suffix, suffix.Length, source, source.Length, options);
+ }
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+
+ [SecuritySafeCritical]
+ internal unsafe int GetHashCodeOfStringCore(string source, CompareOptions options, bool forceRandomizedHashing, long additionalEntropy)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (source.Length == 0)
+ {
+ return 0;
+ }
+
+ int sortKeyLength = Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, null, 0, options);
+
+ // As an optimization, for small sort keys we allocate the buffer on the stack.
+ if (sortKeyLength <= 256)
+ {
+ byte* pSortKey = stackalloc byte[sortKeyLength];
+ Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options);
+ return InternalHashSortKey(pSortKey, sortKeyLength, false, additionalEntropy);
+ }
+
+ byte[] sortKey = new byte[sortKeyLength];
+
+ fixed(byte* pSortKey = sortKey)
+ {
+ Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options);
+ return InternalHashSortKey(pSortKey, sortKeyLength, false, additionalEntropy);
+ }
+ }
+
+ [DllImport(JitHelpers.QCall)]
+ [SuppressUnmanagedCodeSecurity]
+ private static unsafe extern int InternalHashSortKey(byte* sortKey, int sortKeyLength, [MarshalAs(UnmanagedType.Bool)] bool forceRandomizedHashing, long additionalEntropy);
+
+ private static CompareOptions GetOrdinalCompareOptions(CompareOptions options)
+ {
+ if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase)
+ {
+ return CompareOptions.OrdinalIgnoreCase;
+ }
+ else
+ {
+ return CompareOptions.Ordinal;
+ }
+ }
+
+ private static bool CanUseAsciiOrdinalForOptions(CompareOptions options)
+ {
+ // Unlike the other Ignore options, IgnoreSymbols impacts ASCII characters (e.g. ').
+ return (options & CompareOptions.IgnoreSymbols) == 0;
+ }
+
+ private static byte[] GetNullTerminatedUtf8String(string s)
+ {
+ int byteLen = System.Text.Encoding.UTF8.GetByteCount(s);
+
+ // Allocate an extra byte (which defaults to 0) as the null terminator.
+ byte[] buffer = new byte[byteLen + 1];
+
+ int bytesWritten = System.Text.Encoding.UTF8.GetBytes(s, 0, s.Length, buffer, 0);
+
+ Contract.Assert(bytesWritten == byteLen);
+
+ return buffer;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs
new file mode 100644
index 0000000000..744a48b107
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs
@@ -0,0 +1,395 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ public partial class CompareInfo
+ {
+ internal unsafe CompareInfo(CultureInfo culture)
+ {
+ _name = culture._name;
+ InitSort(culture);
+ }
+
+ private void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+
+ const uint LCMAP_SORTHANDLE = 0x20000000;
+
+ _name = culture._name;
+ _sortName = culture.SortName;
+
+ IntPtr handle;
+ int ret = Interop.mincore.LCMapStringEx(_sortName, LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero);
+ _sortHandle = ret > 0 ? handle : IntPtr.Zero;
+ }
+
+ private static unsafe int FindStringOrdinal(
+ uint dwFindStringOrdinalFlags,
+ string stringSource,
+ int offset,
+ int cchSource,
+ string value,
+ int cchValue,
+ bool bIgnoreCase)
+ {
+ fixed (char* pSource = stringSource)
+ fixed (char* pValue = value)
+ {
+ int ret = Interop.mincore.FindStringOrdinal(
+ dwFindStringOrdinalFlags,
+ pSource + offset,
+ cchSource,
+ pValue,
+ cchValue,
+ bIgnoreCase ? 1 : 0);
+ return ret < 0 ? ret : ret + offset;
+ }
+ }
+
+ internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ return FindStringOrdinal(FIND_FROMSTART, source, startIndex, count, value, value.Length, ignoreCase);
+ }
+
+ internal static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ return FindStringOrdinal(FIND_FROMEND, source, startIndex - count + 1, count, value, value.Length, ignoreCase);
+ }
+
+ private unsafe int GetHashCodeOfStringCore(string source, CompareOptions options)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (source.Length == 0)
+ {
+ return 0;
+ }
+
+ int tmpHash = 0;
+
+ fixed (char* pSource = source)
+ {
+ if (Interop.mincore.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName,
+ LCMAP_HASH | (uint)GetNativeCompareFlags(options),
+ pSource, source.Length,
+ &tmpHash, sizeof(int),
+ null, null, _sortHandle) == 0)
+ {
+ Environment.FailFast("LCMapStringEx failed!");
+ }
+ }
+
+ return tmpHash;
+ }
+
+ private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
+ {
+ // Use the OS to compare and then convert the result to expected value by subtracting 2
+ return Interop.mincore.CompareStringOrdinal(string1, count1, string2, count2, true) - 2;
+ }
+
+ private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
+ {
+ Contract.Assert(string1 != null);
+ Contract.Assert(string2 != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pString1 = string1)
+ fixed (char* pString2 = string2)
+ {
+ int result = Interop.mincore.CompareStringEx(
+ pLocaleName,
+ (uint)GetNativeCompareFlags(options),
+ pString1 + offset1,
+ length1,
+ pString2 + offset2,
+ length2,
+ null,
+ null,
+ _sortHandle);
+
+ if (result == 0)
+ {
+ Environment.FailFast("CompareStringEx failed");
+ }
+
+ // Map CompareStringEx return value to -1, 0, 1.
+ return result - 2;
+ }
+ }
+
+ private unsafe int FindString(
+ uint dwFindNLSStringFlags,
+ string lpStringSource,
+ int startSource,
+ int cchSource,
+ string lpStringValue,
+ int startValue,
+ int cchValue)
+ {
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pSource = lpStringSource)
+ fixed (char* pValue = lpStringValue)
+ {
+ char* pS = pSource + startSource;
+ char* pV = pValue + startValue;
+
+ return Interop.mincore.FindNLSStringEx(
+ pLocaleName,
+ dwFindNLSStringFlags,
+ pS,
+ cchSource,
+ pV,
+ cchValue,
+ null,
+ null,
+ null,
+ _sortHandle);
+ }
+ }
+
+ private int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ // TODO: Consider moving this up to the relevent APIs we need to ensure this behavior for
+ // and add a precondition that target is not empty.
+ if (target.Length == 0)
+ return startIndex; // keep Whidbey compatibility
+
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ return FastIndexOfString(source, target, startIndex, count, target.Length, findLastIndex: false);
+ }
+ else
+ {
+ int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options),
+ source,
+ startIndex,
+ count,
+ target,
+ 0,
+ target.Length);
+ if (retValue >= 0)
+ {
+ return retValue + startIndex;
+ }
+ }
+
+ return -1;
+ }
+
+ private int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ // TODO: Consider moving this up to the relevent APIs we need to ensure this behavior for
+ // and add a precondition that target is not empty.
+ if (target.Length == 0)
+ return startIndex; // keep Whidbey compatibility
+
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ return FastIndexOfString(source, target, startIndex, count, target.Length, findLastIndex: true);
+ }
+ else
+ {
+ int retValue = FindString(FIND_FROMEND | (uint)GetNativeCompareFlags(options),
+ source,
+ startIndex - count + 1,
+ count,
+ target,
+ 0,
+ target.Length);
+
+ if (retValue >= 0)
+ {
+ return retValue + startIndex - (count - 1);
+ }
+ }
+
+ return -1;
+ }
+
+ private bool StartsWith(string source, string prefix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(prefix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options),
+ source,
+ 0,
+ source.Length,
+ prefix,
+ 0,
+ prefix.Length) >= 0;
+ }
+
+ private bool EndsWith(string source, string suffix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(suffix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options),
+ source,
+ 0,
+ source.Length,
+ suffix,
+ 0,
+ suffix.Length) >= 0;
+ }
+
+ // PAL ends here
+ [NonSerialized]
+ private readonly IntPtr _sortHandle;
+
+ private const uint LCMAP_HASH = 0x00040000;
+
+ private const int FIND_STARTSWITH = 0x00100000;
+ private const int FIND_ENDSWITH = 0x00200000;
+ private const int FIND_FROMSTART = 0x00400000;
+ private const int FIND_FROMEND = 0x00800000;
+
+ // TODO: Instead of this method could we just have upstack code call IndexOfOrdinal with ignoreCase = false?
+ private static unsafe int FastIndexOfString(string source, string target, int startIndex, int sourceCount, int targetCount, bool findLastIndex)
+ {
+ int retValue = -1;
+
+ int sourceStartIndex = findLastIndex ? startIndex - sourceCount + 1 : startIndex;
+
+#if !TEST_CODEGEN_OPTIMIZATION
+ fixed (char* pSource = source, spTarget = target)
+ {
+ char* spSubSource = pSource + sourceStartIndex;
+#else
+ String.StringPointer spSubSource = source.GetStringPointer(sourceStartIndex);
+ String.StringPointer spTarget = target.GetStringPointer();
+#endif
+ if (findLastIndex)
+ {
+ int startPattern = (sourceCount - 1) - targetCount + 1;
+ if (startPattern < 0)
+ return -1;
+
+ char patternChar0 = spTarget[0];
+ for (int ctrSrc = startPattern; ctrSrc >= 0; ctrSrc--)
+ {
+ if (spSubSource[ctrSrc] != patternChar0)
+ continue;
+
+ int ctrPat;
+ for (ctrPat = 1; ctrPat < targetCount; ctrPat++)
+ {
+ if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat])
+ break;
+ }
+ if (ctrPat == targetCount)
+ {
+ retValue = ctrSrc;
+ break;
+ }
+ }
+
+ if (retValue >= 0)
+ {
+ retValue += startIndex - sourceCount + 1;
+ }
+ }
+ else
+ {
+ int endPattern = (sourceCount - 1) - targetCount + 1;
+ if (endPattern < 0)
+ return -1;
+
+ char patternChar0 = spTarget[0];
+ for (int ctrSrc = 0; ctrSrc <= endPattern; ctrSrc++)
+ {
+ if (spSubSource[ctrSrc] != patternChar0)
+ continue;
+ int ctrPat;
+ for (ctrPat = 1; ctrPat < targetCount; ctrPat++)
+ {
+ if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat])
+ break;
+ }
+ if (ctrPat == targetCount)
+ {
+ retValue = ctrSrc;
+ break;
+ }
+ }
+
+ if (retValue >= 0)
+ {
+ retValue += startIndex;
+ }
+ }
+#if !TEST_CODEGEN_OPTIMIZATION
+ }
+
+ return retValue;
+#endif // TEST_CODEGEN_OPTIMIZATION
+ }
+
+ private const int COMPARE_OPTIONS_ORDINAL = 0x40000000; // Ordinal
+ private const int NORM_IGNORECASE = 0x00000001; // Ignores case. (use LINGUISTIC_IGNORECASE instead)
+ private const int NORM_IGNOREKANATYPE = 0x00010000; // Does not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana will compare as equal.
+ private const int NORM_IGNORENONSPACE = 0x00000002; // Ignores nonspacing. This flag also removes Japanese accent characters. (use LINGUISTIC_IGNOREDIACRITIC instead)
+ private const int NORM_IGNORESYMBOLS = 0x00000004; // Ignores symbols.
+ private const int NORM_IGNOREWIDTH = 0x00020000; // Does not differentiate between a single-byte character and the same character as a double-byte character.
+ private const int NORM_LINGUISTIC_CASING = 0x08000000; // use linguistic rules for casing
+ private const int SORT_STRINGSORT = 0x00001000; // Treats punctuation the same as symbols.
+
+ private static int GetNativeCompareFlags(CompareOptions options)
+ {
+ // Use "linguistic casing" by default (load the culture's casing exception tables)
+ int nativeCompareFlags = NORM_LINGUISTIC_CASING;
+
+ if ((options & CompareOptions.IgnoreCase) != 0) { nativeCompareFlags |= NORM_IGNORECASE; }
+ if ((options & CompareOptions.IgnoreKanaType) != 0) { nativeCompareFlags |= NORM_IGNOREKANATYPE; }
+ if ((options & CompareOptions.IgnoreNonSpace) != 0) { nativeCompareFlags |= NORM_IGNORENONSPACE; }
+ if ((options & CompareOptions.IgnoreSymbols) != 0) { nativeCompareFlags |= NORM_IGNORESYMBOLS; }
+ if ((options & CompareOptions.IgnoreWidth) != 0) { nativeCompareFlags |= NORM_IGNOREWIDTH; }
+ if ((options & CompareOptions.StringSort) != 0) { nativeCompareFlags |= SORT_STRINGSORT; }
+
+ // TODO: Can we try for GetNativeCompareFlags to never
+ // take Ordinal or OrdinalIgnoreCase. This value is not part of Win32, we just handle it special
+ // in some places.
+ // Suffix & Prefix shouldn't use this, make sure to turn off the NORM_LINGUISTIC_CASING flag
+ if (options == CompareOptions.Ordinal) { nativeCompareFlags = COMPARE_OPTIONS_ORDINAL; }
+
+ Contract.Assert(((options & ~(CompareOptions.IgnoreCase |
+ CompareOptions.IgnoreKanaType |
+ CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreSymbols |
+ CompareOptions.IgnoreWidth |
+ CompareOptions.StringSort)) == 0) ||
+ (options == CompareOptions.Ordinal), "[CompareInfo.GetNativeCompareFlags]Expected all flags to be handled");
+
+ return nativeCompareFlags;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.cs
new file mode 100644
index 0000000000..77778af23c
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.cs
@@ -0,0 +1,925 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+//
+// Purpose: This class implements a set of methods for comparing
+// strings.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Threading;
+
+namespace System.Globalization
+{
+ [Flags]
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public enum CompareOptions
+ {
+ None = 0x00000000,
+ IgnoreCase = 0x00000001,
+ IgnoreNonSpace = 0x00000002,
+ IgnoreSymbols = 0x00000004,
+ IgnoreKanaType = 0x00000008, // ignore kanatype
+ IgnoreWidth = 0x00000010, // ignore width
+ OrdinalIgnoreCase = 0x10000000, // This flag can not be used with other flags.
+ StringSort = 0x20000000, // use string sort method
+ Ordinal = 0x40000000, // This flag can not be used with other flags.
+ }
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class CompareInfo : IDeserializationCallback
+ {
+ // Mask used to check if IndexOf()/LastIndexOf()/IsPrefix()/IsPostfix() has the right flags.
+ private const CompareOptions ValidIndexMaskOffFlags =
+ ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
+
+ // Mask used to check if Compare() has the right flags.
+ private const CompareOptions ValidCompareMaskOffFlags =
+ ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
+
+ // Mask used to check if GetHashCodeOfString() has the right flags.
+ private const CompareOptions ValidHashCodeOfStringMaskOffFlags =
+ ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
+
+ //
+ // CompareInfos have an interesting identity. They are attached to the locale that created them,
+ // ie: en-US would have an en-US sort. For haw-US (custom), then we serialize it as haw-US.
+ // The interesting part is that since haw-US doesn't have its own sort, it has to point at another
+ // locale, which is what SCOMPAREINFO does.
+
+ [OptionalField(VersionAdded = 2)]
+ private String _name; // The name used to construct this CompareInfo
+ [NonSerialized]
+ private String _sortName; // The name that defines our behavior
+
+ /*=================================GetCompareInfo==========================
+ **Action: Get the CompareInfo for the specified culture.
+ **Returns: The CompareInfo for the specified culture.
+ **Arguments:
+ ** name the name of the culture.
+ **Exceptions:
+ ** ArgumentException if name is invalid.
+ ============================================================================*/
+
+ public static CompareInfo GetCompareInfo(String name)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ Contract.EndContractBlock();
+
+ return CultureInfo.GetCultureInfo(name).CompareInfo;
+ }
+
+ [OnDeserializing]
+ private void OnDeserializing(StreamingContext ctx)
+ {
+ _name = null;
+ }
+
+ void IDeserializationCallback.OnDeserialization(Object sender)
+ {
+ OnDeserialized();
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ OnDeserialized();
+ }
+
+ private void OnDeserialized()
+ {
+ if (_name != null)
+ {
+ InitSort(CultureInfo.GetCultureInfo(_name));
+ }
+ }
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx) { }
+
+ ///////////////////////////----- Name -----/////////////////////////////////
+ //
+ // Returns the name of the culture (well actually, of the sort).
+ // Very important for providing a non-LCID way of identifying
+ // what the sort is.
+ //
+ // Note that this name isn't dereferenced in case the CompareInfo is a different locale
+ // which is consistent with the behaviors of earlier versions. (so if you ask for a sort
+ // and the locale's changed behavior, then you'll get changed behavior, which is like
+ // what happens for a version update)
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual String Name
+ {
+ get
+ {
+ Contract.Assert(_name != null, "CompareInfo.Name Expected _name to be set");
+ if (_name == "zh-CHT" || _name == "zh-CHS")
+ {
+ return _name;
+ }
+
+ return _sortName;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Compare
+ //
+ // Compares the two strings with the given options. Returns 0 if the
+ // two strings are equal, a number less than 0 if string1 is less
+ // than string2, and a number greater than 0 if string1 is greater
+ // than string2.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public virtual int Compare(String string1, String string2)
+ {
+ return (Compare(string1, string2, CompareOptions.None));
+ }
+
+ public unsafe virtual int Compare(String string1, String string2, CompareOptions options)
+ {
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return String.Compare(string1, string2, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Verify the options before we do any real comparison.
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ if (options != CompareOptions.Ordinal)
+ {
+ throw new ArgumentException(SR.Argument_CompareOptionOrdinal, "options");
+ }
+ return String.CompareOrdinal(string1, string2);
+ }
+
+ if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ //Our paradigm is that null sorts less than any other string and
+ //that two nulls sort as equal.
+ if (string1 == null)
+ {
+ if (string2 == null)
+ {
+ return (0); // Equal
+ }
+ return (-1); // null < non-null
+ }
+ if (string2 == null)
+ {
+ return (1); // non-null > null
+ }
+
+ return CompareString(string1, 0, string1.Length, string2, 0, string2.Length, options);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Compare
+ //
+ // Compares the specified regions of the two strings with the given
+ // options.
+ // Returns 0 if the two strings are equal, a number less than 0 if
+ // string1 is less than string2, and a number greater than 0 if
+ // string1 is greater than string2.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public unsafe virtual int Compare(String string1, int offset1, int length1, String string2, int offset2, int length2)
+ {
+ return Compare(string1, offset1, length1, string2, offset2, length2, 0);
+ }
+
+
+ public unsafe virtual int Compare(String string1, int offset1, String string2, int offset2, CompareOptions options)
+ {
+ return Compare(string1, offset1, string1 == null ? 0 : string1.Length - offset1,
+ string2, offset2, string2 == null ? 0 : string2.Length - offset2, options);
+ }
+
+
+ public unsafe virtual int Compare(String string1, int offset1, String string2, int offset2)
+ {
+ return Compare(string1, offset1, string2, offset2, 0);
+ }
+
+
+ public unsafe virtual int Compare(String string1, int offset1, int length1, String string2, int offset2, int length2, CompareOptions options)
+ {
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ int result = String.Compare(string1, offset1, string2, offset2, length1 < length2 ? length1 : length2, StringComparison.OrdinalIgnoreCase);
+ if ((length1 != length2) && result == 0)
+ return (length1 > length2 ? 1 : -1);
+ return (result);
+ }
+
+ // Verify inputs
+ if (length1 < 0 || length2 < 0)
+ {
+ throw new ArgumentOutOfRangeException((length1 < 0) ? "length1" : "length2", SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ if (offset1 < 0 || offset2 < 0)
+ {
+ throw new ArgumentOutOfRangeException((offset1 < 0) ? "offset1" : "offset2", SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ if (offset1 > (string1 == null ? 0 : string1.Length) - length1)
+ {
+ throw new ArgumentOutOfRangeException("string1", SR.ArgumentOutOfRange_OffsetLength);
+ }
+ if (offset2 > (string2 == null ? 0 : string2.Length) - length2)
+ {
+ throw new ArgumentOutOfRangeException("string2", SR.ArgumentOutOfRange_OffsetLength);
+ }
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ if (options != CompareOptions.Ordinal)
+ {
+ throw new ArgumentException(SR.Argument_CompareOptionOrdinal,
+ "options");
+ }
+ }
+ else if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ //
+ // Check for the null case.
+ //
+ if (string1 == null)
+ {
+ if (string2 == null)
+ {
+ return (0);
+ }
+ return (-1);
+ }
+ if (string2 == null)
+ {
+ return (1);
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return CompareOrdinal(string1, offset1, length1,
+ string2, offset2, length2);
+ }
+ return CompareString(string1, offset1, length1,
+ string2, offset2, length2,
+ options);
+ }
+
+ private static int CompareOrdinal(string string1, int offset1, int length1, string string2, int offset2, int length2)
+ {
+ int result = String.CompareOrdinal(string1, offset1, string2, offset2,
+ (length1 < length2 ? length1 : length2));
+ if ((length1 != length2) && result == 0)
+ {
+ return (length1 > length2 ? 1 : -1);
+ }
+ return (result);
+ }
+
+ //
+ // CompareOrdinalIgnoreCase compare two string oridnally with ignoring the case.
+ // it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by
+ // calling the OS.
+ //
+ internal static unsafe int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB)
+ {
+ Contract.Assert(indexA + lengthA <= strA.Length);
+ Contract.Assert(indexB + lengthB <= strB.Length);
+
+ int length = Math.Min(lengthA, lengthB);
+ int range = length;
+
+ fixed (char* ap = strA) fixed (char* bp = strB)
+ {
+ char* a = ap + indexA;
+ char* b = bp + indexB;
+
+ while (length != 0 && (*a <= 0x80) && (*b <= 0x80))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA == charB)
+ {
+ a++; b++;
+ length--;
+ continue;
+ }
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
+ if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+
+ //Return the (case-insensitive) difference between them.
+ if (charA != charB)
+ return charA - charB;
+
+ // Next char
+ a++; b++;
+ length--;
+ }
+
+ if (length == 0)
+ return lengthA - lengthB;
+
+ range -= length;
+
+ return CompareStringOrdinalIgnoreCase(a, lengthA - range, b, lengthB - range);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsPrefix
+ //
+ // Determines whether prefix is a prefix of string. If prefix equals
+ // String.Empty, true is returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public unsafe virtual bool IsPrefix(String source, String prefix, CompareOptions options)
+ {
+ if (source == null || prefix == null)
+ {
+ throw new ArgumentNullException((source == null ? "source" : "prefix"),
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ if (prefix.Length == 0)
+ {
+ return (true);
+ }
+
+ if (source.Length == 0)
+ {
+ return false;
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return source.StartsWith(prefix, StringComparison.Ordinal);
+ }
+
+ if ((options & ValidIndexMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ return StartsWith(source, prefix, options);
+ }
+
+ public virtual bool IsPrefix(String source, String prefix)
+ {
+ return (IsPrefix(source, prefix, 0));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsSuffix
+ //
+ // Determines whether suffix is a suffix of string. If suffix equals
+ // String.Empty, true is returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public unsafe virtual bool IsSuffix(String source, String suffix, CompareOptions options)
+ {
+ if (source == null || suffix == null)
+ {
+ throw new ArgumentNullException((source == null ? "source" : "suffix"),
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ if (suffix.Length == 0)
+ {
+ return (true);
+ }
+
+ if (source.Length == 0)
+ {
+ return false;
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.EndsWith(suffix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return source.EndsWith(suffix, StringComparison.Ordinal);
+ }
+
+ if ((options & ValidIndexMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ return EndsWith(source, suffix, options);
+ }
+
+
+ public virtual bool IsSuffix(String source, String suffix)
+ {
+ return (IsSuffix(source, suffix, 0));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IndexOf
+ //
+ // Returns the first index where value is found in string. The
+ // search starts from startIndex and ends at endIndex. Returns -1 if
+ // the specified value is not found. If value equals String.Empty,
+ // startIndex is returned. Throws IndexOutOfRange if startIndex or
+ // endIndex is less than zero or greater than the length of string.
+ // Throws ArgumentException if value is null.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public unsafe virtual int IndexOf(String source, char value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, char value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, char value, int startIndex, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, startIndex, source.Length - startIndex, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, int startIndex, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, startIndex, source.Length - startIndex, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, char value, int startIndex, int count)
+ {
+ return IndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, int startIndex, int count)
+ {
+ return IndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+ public unsafe virtual int IndexOf(String source, char value, int startIndex, int count, CompareOptions options)
+ {
+ // Validate inputs
+ if (source == null)
+ throw new ArgumentNullException("source");
+
+ if (startIndex < 0 || startIndex > source.Length)
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+
+ if (count < 0 || startIndex > source.Length - count)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+ Contract.EndContractBlock();
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.IndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ return IndexOfCore(source, new string(value, 1), startIndex, count, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, int startIndex, int count, CompareOptions options)
+ {
+ // Validate inputs
+ if (source == null)
+ throw new ArgumentNullException("source");
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (startIndex > source.Length)
+ {
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+ }
+ Contract.EndContractBlock();
+
+ // In Everett we used to return -1 for empty string even if startIndex is negative number so we keeping same behavior here.
+ // We return 0 if both source and value are empty strings for Everett compatibility too.
+ if (source.Length == 0)
+ {
+ if (value.Length == 0)
+ {
+ return 0;
+ }
+ return -1;
+ }
+
+ if (startIndex < 0)
+ {
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+ }
+
+ if (count < 0 || startIndex > source.Length - count)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ }
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ return IndexOfCore(source, value, startIndex, count, options);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // LastIndexOf
+ //
+ // Returns the last index where value is found in string. The
+ // search starts from startIndex and ends at endIndex. Returns -1 if
+ // the specified value is not found. If value equals String.Empty,
+ // endIndex is returned. Throws IndexOutOfRange if startIndex or
+ // endIndex is less than zero or greater than the length of string.
+ // Throws ArgumentException if value is null.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public unsafe virtual int LastIndexOf(String source, char value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, CompareOptions.None);
+ }
+
+
+ public virtual int LastIndexOf(String source, String value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, CompareOptions.None);
+ }
+
+
+ public virtual int LastIndexOf(String source, char value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, options);
+ }
+
+ public unsafe virtual int LastIndexOf(String source, String value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, char value, int startIndex, CompareOptions options)
+ {
+ return LastIndexOf(source, value, startIndex, startIndex + 1, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, String value, int startIndex, CompareOptions options)
+ {
+ return LastIndexOf(source, value, startIndex, startIndex + 1, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, char value, int startIndex, int count)
+ {
+ return LastIndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, String value, int startIndex, int count)
+ {
+ return LastIndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, char value, int startIndex, int count, CompareOptions options)
+ {
+ // Verify Arguments
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 &&
+ (options != CompareOptions.Ordinal) &&
+ (options != CompareOptions.OrdinalIgnoreCase))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ // Special case for 0 length input strings
+ if (source.Length == 0 && (startIndex == -1 || startIndex == 0))
+ return -1;
+
+ // Make sure we're not out of range
+ if (startIndex < 0 || startIndex > source.Length)
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+
+ // Make sure that we allow startIndex == source.Length
+ if (startIndex == source.Length)
+ {
+ startIndex--;
+ if (count > 0)
+ count--;
+ }
+
+ // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
+ if (count < 0 || startIndex - count + 1 < 0)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.LastIndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase);
+ }
+
+ return LastIndexOfCore(source, value.ToString(), startIndex, count, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, String value, int startIndex, int count, CompareOptions options)
+ {
+ // Verify Arguments
+ if (source == null)
+ throw new ArgumentNullException("source");
+ if (value == null)
+ throw new ArgumentNullException("value");
+ Contract.EndContractBlock();
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 &&
+ (options != CompareOptions.Ordinal) &&
+ (options != CompareOptions.OrdinalIgnoreCase))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ // Special case for 0 length input strings
+ if (source.Length == 0 && (startIndex == -1 || startIndex == 0))
+ return (value.Length == 0) ? 0 : -1;
+
+ // Make sure we're not out of range
+ if (startIndex < 0 || startIndex > source.Length)
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+
+ // Make sure that we allow startIndex == source.Length
+ if (startIndex == source.Length)
+ {
+ startIndex--;
+ if (count > 0)
+ count--;
+
+ // If we are looking for nothing, just return 0
+ if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
+ return startIndex;
+ }
+
+ // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
+ if (count < 0 || startIndex - count + 1 < 0)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ }
+
+ return LastIndexOfCore(source, value, startIndex, count, options);
+ }
+
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Equals
+ //
+ // Implements Object.Equals(). Returns a boolean indicating whether
+ // or not object refers to the same CompareInfo as the current
+ // instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override bool Equals(Object value)
+ {
+ CompareInfo that = value as CompareInfo;
+
+ if (that != null)
+ {
+ return this.Name == that.Name;
+ }
+
+ return (false);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCode
+ //
+ // Implements Object.GetHashCode(). Returns the hash code for the
+ // CompareInfo. The hash code is guaranteed to be the same for
+ // CompareInfo A and B where A.Equals(B) is true.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override int GetHashCode()
+ {
+ return (this.Name.GetHashCode());
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCodeOfString
+ //
+ // This internal method allows a method that allows the equivalent of creating a Sortkey for a
+ // string from CompareInfo, and generate a hashcode value from it. It is not very convenient
+ // to use this method as is and it creates an unnecessary Sortkey object that will be GC'ed.
+ //
+ // The hash code is guaranteed to be the same for string A and B where A.Equals(B) is true and both
+ // the CompareInfo and the CompareOptions are the same. If two different CompareInfo objects
+ // treat the string the same way, this implementation will treat them differently (the same way that
+ // Sortkey does at the moment).
+ //
+ // This method will never be made public itself, but public consumers of it could be created, e.g.:
+ //
+ // string.GetHashCode(CultureInfo)
+ // string.GetHashCode(CompareInfo)
+ // string.GetHashCode(CultureInfo, CompareOptions)
+ // string.GetHashCode(CompareInfo, CompareOptions)
+ // etc.
+ //
+ // (the methods above that take a CultureInfo would use CultureInfo.CompareInfo)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ internal int GetHashCodeOfString(string source, CompareOptions options)
+ {
+ //
+ // Parameter validation
+ //
+ if (null == source)
+ {
+ throw new ArgumentNullException("source");
+ }
+
+ if ((options & ValidHashCodeOfStringMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+ Contract.EndContractBlock();
+
+ return GetHashCodeOfStringCore(source, options);
+ }
+
+ public virtual int GetHashCode(string source, CompareOptions options)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException("source");
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return source.GetHashCode();
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return TextInfo.GetHashCodeOrdinalIgnoreCase(source);
+ }
+
+ //
+ // GetHashCodeOfString does more parameters validation. basically will throw when
+ // having Ordinal, OrdinalIgnoreCase and StringSort
+ //
+
+ return GetHashCodeOfString(source, options);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Implements Object.ToString(). Returns a string describing the
+ // CompareInfo.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override String ToString()
+ {
+ return ("CompareInfo - " + this.Name);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
new file mode 100644
index 0000000000..58aae2f40b
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
@@ -0,0 +1,304 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+namespace System.Globalization
+{
+ internal partial class CultureData
+ {
+ // ICU constants
+ const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value
+ const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name
+ const string ICU_COLLATION_KEYWORD = "@collation=";
+
+ /// <summary>
+ /// This method uses the sRealName field (which is initialized by the constructor before this is called) to
+ /// initialize the rest of the state of CultureData based on the underlying OS globalization library.
+ /// </summary>
+ [SecuritySafeCritical]
+ private unsafe bool InitCultureData()
+ {
+ Contract.Assert(_sRealName != null);
+
+ string alternateSortName = string.Empty;
+ string realNameBuffer = _sRealName;
+
+ // Basic validation
+ if (realNameBuffer.Contains("@"))
+ {
+ return false; // don't allow ICU variants to come in directly
+ }
+
+ // Replace _ (alternate sort) with @collation= for ICU
+ int index = realNameBuffer.IndexOf('_');
+ if (index > 0)
+ {
+ if (index >= (realNameBuffer.Length - 1) // must have characters after _
+ || realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed
+ {
+ return false; // fail
+ }
+ alternateSortName = realNameBuffer.Substring(index + 1);
+ realNameBuffer = realNameBuffer.Substring(0, index) + ICU_COLLATION_KEYWORD + alternateSortName;
+ }
+
+ // Get the locale name from ICU
+ if (!GetLocaleName(realNameBuffer, out _sWindowsName))
+ {
+ return false; // fail
+ }
+
+ // Replace the ICU collation keyword with an _
+ index = _sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
+ if (index >= 0)
+ {
+ _sName = _sWindowsName.Substring(0, index) + "_" + alternateSortName;
+ }
+ else
+ {
+ _sName = _sWindowsName;
+ }
+ _sRealName = _sName;
+ _sSpecificCulture = _sRealName; // we don't attempt to find a non-neutral locale if a neutral is passed in (unlike win32)
+
+ _iLanguage = this.ILANGUAGE;
+ if (_iLanguage == 0)
+ {
+ _iLanguage = LOCALE_CUSTOM_UNSPECIFIED;
+ }
+
+ _bNeutral = (this.SISO3166CTRYNAME.Length == 0);
+
+ // Remove the sort from sName unless custom culture
+ if (!_bNeutral)
+ {
+ if (!IsCustomCultureId(_iLanguage))
+ {
+ _sName = _sWindowsName.Substring(0, index);
+ }
+ }
+ return true;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool GetLocaleName(string localeName, out string windowsName)
+ {
+ // Get the locale name from ICU
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ if (!Interop.GlobalizationInterop.GetLocaleName(localeName, sb, sb.Capacity))
+ {
+ StringBuilderCache.Release(sb);
+ windowsName = null;
+ return false; // fail
+ }
+
+ // Success - use the locale name returned which may be different than realNameBuffer (casing)
+ windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
+ return true;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool GetDefaultLocaleName(out string windowsName)
+ {
+ // Get the default (system) locale name from ICU
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ if (!Interop.GlobalizationInterop.GetDefaultLocaleName(sb, sb.Capacity))
+ {
+ StringBuilderCache.Release(sb);
+ windowsName = null;
+ return false; // fail
+ }
+
+ // Success - use the locale name returned which may be different than realNameBuffer (casing)
+ windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
+ return true;
+ }
+
+ private string GetLocaleInfo(LocaleStringData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo] Expected _sWindowsName to be populated already");
+ return GetLocaleInfo(_sWindowsName, type);
+ }
+
+ // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
+ // "windows" name, which can be specific for downlevel (< windows 7) os's.
+ [SecuritySafeCritical]
+ private string GetLocaleInfo(string localeName, LocaleStringData type)
+ {
+ Contract.Assert(localeName != null, "[CultureData.GetLocaleInfo] Expected localeName to be not be null");
+
+ switch (type)
+ {
+ case LocaleStringData.NegativeInfinitySymbol:
+ // not an equivalent in ICU; prefix the PositiveInfinitySymbol with NegativeSign
+ return GetLocaleInfo(localeName, LocaleStringData.NegativeSign) +
+ GetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol);
+ }
+
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
+
+ bool result = Interop.GlobalizationInterop.GetLocaleInfoString(localeName, (uint)type, sb, sb.Capacity);
+ if (!result)
+ {
+ // Failed, just use empty string
+ StringBuilderCache.Release(sb);
+ Contract.Assert(false, "[CultureData.GetLocaleInfo(LocaleStringData)] Failed");
+ return String.Empty;
+ }
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+
+ [SecuritySafeCritical]
+ private int GetLocaleInfo(LocaleNumberData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already");
+
+ switch (type)
+ {
+ case LocaleNumberData.CalendarType:
+ // returning 0 will cause the first supported calendar to be returned, which is the preferred calendar
+ return 0;
+ }
+
+
+ int value = 0;
+ bool result = Interop.GlobalizationInterop.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value);
+ if (!result)
+ {
+ // Failed, just use 0
+ Contract.Assert(false, "[CultureData.GetLocaleInfo(LocaleNumberData)] failed");
+ }
+
+ return value;
+ }
+
+ [SecuritySafeCritical]
+ private int[] GetLocaleInfo(LocaleGroupingData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already");
+
+ int primaryGroupingSize = 0;
+ int secondaryGroupingSize = 0;
+ bool result = Interop.GlobalizationInterop.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize);
+ if (!result)
+ {
+ Contract.Assert(false, "[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed");
+ }
+
+ if (secondaryGroupingSize == 0)
+ {
+ return new int[] { primaryGroupingSize };
+ }
+
+ return new int[] { primaryGroupingSize, secondaryGroupingSize };
+ }
+
+ private string GetTimeFormatString()
+ {
+ return GetTimeFormatString(false);
+ }
+
+ [SecuritySafeCritical]
+ private string GetTimeFormatString(bool shortFormat)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already");
+
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
+
+ bool result = Interop.GlobalizationInterop.GetLocaleTimeFormat(_sWindowsName, shortFormat, sb, sb.Capacity);
+ if (!result)
+ {
+ // Failed, just use empty string
+ StringBuilderCache.Release(sb);
+ Contract.Assert(false, "[CultureData.GetTimeFormatString(bool shortFormat)] Failed");
+ return String.Empty;
+ }
+
+ return ConvertIcuTimeFormatString(StringBuilderCache.GetStringAndRelease(sb));
+ }
+
+ private int GetFirstDayOfWeek()
+ {
+ return this.GetLocaleInfo(LocaleNumberData.FirstDayOfWeek);
+ }
+
+ private String[] GetTimeFormats()
+ {
+ string format = GetTimeFormatString(false);
+ return new string[] { format };
+ }
+
+ private String[] GetShortTimeFormats()
+ {
+ string format = GetTimeFormatString(true);
+ return new string[] { format };
+ }
+
+ private static CultureData GetCultureDataFromRegionName(String regionName)
+ {
+ // no support to lookup by region name, other than the hard-coded list in CultureData
+ return null;
+ }
+
+ private static string GetLanguageDisplayName(string cultureName)
+ {
+ return new CultureInfo(cultureName).m_cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
+ }
+
+ private static string GetRegionDisplayName(string isoCountryCode)
+ {
+ // use the fallback which is to return NativeName
+ return null;
+ }
+
+ private static CultureInfo GetUserDefaultCulture()
+ {
+ return CultureInfo.GetUserDefaultCulture();
+ }
+
+ private static string ConvertIcuTimeFormatString(string icuFormatString)
+ {
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ bool amPmAdded = false;
+
+ for (int i = 0; i < icuFormatString.Length; i++)
+ {
+ switch(icuFormatString[i])
+ {
+ case ':':
+ case '.':
+ case 'H':
+ case 'h':
+ case 'm':
+ case 's':
+ sb.Append(icuFormatString[i]);
+ break;
+
+ case ' ':
+ case '\u00A0':
+ // Convert nonbreaking spaces into regular spaces
+ sb.Append(' ');
+ break;
+
+ case 'a': // AM/PM
+ if (!amPmAdded)
+ {
+ amPmAdded = true;
+ sb.Append("tt");
+ }
+ break;
+
+ }
+ }
+
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs b/src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs
new file mode 100644
index 0000000000..9969ecbd81
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs
@@ -0,0 +1,561 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Text;
+using Internal.Runtime.Augments;
+
+namespace System.Globalization
+{
+ internal partial class CultureData
+ {
+ private const uint LOCALE_NOUSEROVERRIDE = 0x80000000;
+ private const uint LOCALE_RETURN_NUMBER = 0x20000000;
+ private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A;
+
+ private const uint TIME_NOSECONDS = 0x00000002;
+
+ /// <summary>
+ /// Check with the OS to see if this is a valid culture.
+ /// If so we populate a limited number of fields. If its not valid we return false.
+ ///
+ /// The fields we populate:
+ ///
+ /// sWindowsName -- The name that windows thinks this culture is, ie:
+ /// en-US if you pass in en-US
+ /// de-DE_phoneb if you pass in de-DE_phoneb
+ /// fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
+ /// fj if you pass in fj (neutral, post-Windows 7 machine)
+ ///
+ /// sRealName -- The name you used to construct the culture, in pretty form
+ /// en-US if you pass in EN-us
+ /// en if you pass in en
+ /// de-DE_phoneb if you pass in de-DE_phoneb
+ ///
+ /// sSpecificCulture -- The specific culture for this culture
+ /// en-US for en-US
+ /// en-US for en
+ /// de-DE_phoneb for alt sort
+ /// fj-FJ for fj (neutral)
+ ///
+ /// sName -- The IETF name of this culture (ie: no sort info, could be neutral)
+ /// en-US if you pass in en-US
+ /// en if you pass in en
+ /// de-DE if you pass in de-DE_phoneb
+ ///
+ /// bNeutral -- TRUE if it is a neutral locale
+ ///
+ /// For a neutral we just populate the neutral name, but we leave the windows name pointing to the
+ /// windows locale that's going to provide data for us.
+ /// </summary>
+ private unsafe bool InitCultureData()
+ {
+ const int LOCALE_NAME_MAX_LENGTH = 85;
+
+ const uint LOCALE_ILANGUAGE = 0x00000001;
+ const uint LOCALE_INEUTRAL = 0x00000071;
+ const uint LOCALE_SNAME = 0x0000005c;
+
+ int result;
+ string realNameBuffer = _sRealName;
+ char* pBuffer = stackalloc char[LOCALE_NAME_MAX_LENGTH];
+
+ result = Interop.mincore.GetLocaleInfoEx(realNameBuffer, LOCALE_SNAME, pBuffer, LOCALE_NAME_MAX_LENGTH);
+
+ // Did it fail?
+ if (result == 0)
+ {
+ return false;
+ }
+
+ // It worked, note that the name is the locale name, so use that (even for neutrals)
+ // We need to clean up our "real" name, which should look like the windows name right now
+ // so overwrite the input with the cleaned up name
+ _sRealName = new String(pBuffer, 0, result - 1);
+ realNameBuffer = _sRealName;
+
+ // Check for neutrality, don't expect to fail
+ // (buffer has our name in it, so we don't have to do the gc. stuff)
+
+ result = Interop.mincore.GetLocaleInfoEx(realNameBuffer, LOCALE_INEUTRAL | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char));
+ if (result == 0)
+ {
+ return false;
+ }
+
+ // Remember our neutrality
+ _bNeutral = *((uint*)pBuffer) != 0;
+
+ // Note: Parents will be set dynamically
+
+ // Start by assuming the windows name'll be the same as the specific name since windows knows
+ // about specifics on all versions. Only for downlevel Neutral locales does this have to change.
+ _sWindowsName = realNameBuffer;
+
+ // Neutrals and non-neutrals are slightly different
+ if (_bNeutral)
+ {
+ // Neutral Locale
+
+ // IETF name looks like neutral name
+ _sName = realNameBuffer;
+
+ // Specific locale name is whatever ResolveLocaleName (win7+) returns.
+ // (Buffer has our name in it, and we can recycle that because windows resolves it before writing to the buffer)
+ result = Interop.mincore.ResolveLocaleName(realNameBuffer, pBuffer, LOCALE_NAME_MAX_LENGTH);
+
+ // 0 is failure, 1 is invariant (""), which we expect
+ if (result < 1)
+ {
+ return false;
+ }
+ // We found a locale name, so use it.
+ // In vista this should look like a sort name (de-DE_phoneb) or a specific culture (en-US) and be in the "pretty" form
+ _sSpecificCulture = new String(pBuffer, 0, result - 1);
+ }
+ else
+ {
+ // Specific Locale
+
+ // Specific culture's the same as the locale name since we know its not neutral
+ // On mac we'll use this as well, even for neutrals. There's no obvious specific
+ // culture to use and this isn't exposed, but behaviorally this is correct on mac.
+ // Note that specifics include the sort name (de-DE_phoneb)
+ _sSpecificCulture = realNameBuffer;
+
+ _sName = realNameBuffer;
+
+ // We need the IETF name (sname)
+ // If we aren't an alt sort locale then this is the same as the windows name.
+ // If we are an alt sort locale then this is the same as the part before the _ in the windows name
+ // This is for like de-DE_phoneb and es-ES_tradnl that hsouldn't have the _ part
+
+ result = Interop.mincore.GetLocaleInfoEx(realNameBuffer, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char));
+ if (result == 0)
+ {
+ return false;
+ }
+
+ _iLanguage = *((int*)pBuffer);
+
+ if (!IsCustomCultureId(_iLanguage))
+ {
+ // not custom locale
+ int index = realNameBuffer.IndexOf('_');
+ if (index > 0 && index < realNameBuffer.Length)
+ {
+ _sName = realNameBuffer.Substring(0, index);
+ }
+ }
+ }
+
+ // It succeeded.
+ return true;
+ }
+
+ private string GetLocaleInfo(LocaleStringData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already");
+ return GetLocaleInfo(_sWindowsName, type);
+ }
+
+ // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
+ // "windows" name, which can be specific for downlevel (< windows 7) os's.
+ private string GetLocaleInfo(string localeName, LocaleStringData type)
+ {
+ uint lctype = (uint)type;
+
+ return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride);
+ }
+
+ private int GetLocaleInfo(LocaleNumberData type)
+ {
+ uint lctype = (uint)type;
+
+ // Fix lctype if we don't want overrides
+ if (!UseUserOverride)
+ {
+ lctype |= LOCALE_NOUSEROVERRIDE;
+ }
+
+ // Ask OS for data, note that we presume it returns success, so we have to know that
+ // sWindowsName is valid before calling.
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
+ int result = Interop.mincore.GetLocaleInfoExInt(_sWindowsName, lctype);
+
+ return result;
+ }
+
+ private int[] GetLocaleInfo(LocaleGroupingData type)
+ {
+ return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride));
+ }
+
+ private string GetTimeFormatString()
+ {
+ const uint LOCALE_STIMEFORMAT = 0x00001003;
+
+ return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, LOCALE_STIMEFORMAT, UseUserOverride));
+ }
+
+ private int GetFirstDayOfWeek()
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
+
+ const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C;
+
+ int result = Interop.mincore.GetLocaleInfoExInt(_sWindowsName, LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? LOCALE_NOUSEROVERRIDE : 0));
+
+ // Win32 and .NET disagree on the numbering for days of the week, so we have to convert.
+ return ConvertFirstDayOfWeekMonToSun(result);
+ }
+
+ private String[] GetTimeFormats()
+ {
+ // Note that this gets overrides for us all the time
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already");
+ String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride));
+
+ return result;
+ }
+
+ private String[] GetShortTimeFormats()
+ {
+ // Note that this gets overrides for us all the time
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already");
+ String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, TIME_NOSECONDS, UseUserOverride));
+
+ return result;
+ }
+
+ // Enumerate all system cultures and then try to find out which culture has
+ // region name match the requested region name
+ private static CultureData GetCultureDataFromRegionName(String regionName)
+ {
+ Contract.Assert(regionName != null);
+
+ const uint LOCALE_SUPPLEMENTAL = 0x00000002;
+ const uint LOCALE_SPECIFICDATA = 0x00000020;
+
+ EnumLocaleData context = new EnumLocaleData();
+ context.cultureName = null;
+ context.regionName = regionName;
+
+ GCHandle contextHandle = GCHandle.Alloc(context);
+ try
+ {
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, Interop.BOOL>>(EnumSystemLocalesProc);
+ Interop.mincore.EnumSystemLocalesEx(callback, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, (IntPtr)contextHandle, IntPtr.Zero);
+ }
+ finally
+ {
+ contextHandle.Free();
+ }
+
+ if (context.cultureName != null)
+ {
+ // we got a matched culture
+ return GetCultureData(context.cultureName, true);
+ }
+
+ return null;
+ }
+
+ private static string GetLanguageDisplayName(string cultureName)
+ {
+ return WinRTInterop.Callbacks.GetLanguageDisplayName(cultureName);
+ }
+
+ private static string GetRegionDisplayName(string isoCountryCode)
+ {
+ return WinRTInterop.Callbacks.GetRegionDisplayName(isoCountryCode);
+ }
+
+ private static CultureInfo GetUserDefaultCulture()
+ {
+ return (CultureInfo)WinRTInterop.Callbacks.GetUserDefaultCulture();
+ }
+
+ // PAL methods end here.
+
+ private static string GetLocaleInfoFromLCType(string localeName, uint lctype, bool useUserOveride)
+ {
+ Contract.Assert(localeName != null, "[CultureData.GetLocaleInfoFromLCType] Expected localeName to be not be null");
+
+ // Fix lctype if we don't want overrides
+ if (!useUserOveride)
+ {
+ lctype |= LOCALE_NOUSEROVERRIDE;
+ }
+
+ // Ask OS for data
+ string result = Interop.mincore.GetLocaleInfoEx(localeName, lctype);
+ if (result == null)
+ {
+ // Failed, just use empty string
+ result = String.Empty;
+ }
+
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Reescape a Win32 style quote string as a NLS+ style quoted string
+ //
+ // This is also the escaping style used by custom culture data files
+ //
+ // NLS+ uses \ to escape the next character, whether in a quoted string or
+ // not, so we always have to change \ to \\.
+ //
+ // NLS+ uses \' to escape a quote inside a quoted string so we have to change
+ // '' to \' (if inside a quoted string)
+ //
+ // We don't build the stringbuilder unless we find something to change
+ ////////////////////////////////////////////////////////////////////////////
+ internal static String ReescapeWin32String(String str)
+ {
+ // If we don't have data, then don't try anything
+ if (str == null)
+ return null;
+
+ StringBuilder result = null;
+
+ bool inQuote = false;
+ for (int i = 0; i < str.Length; i++)
+ {
+ // Look for quote
+ if (str[i] == '\'')
+ {
+ // Already in quote?
+ if (inQuote)
+ {
+ // See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote?
+ if (i + 1 < str.Length && str[i + 1] == '\'')
+ {
+ // Found another ', so we have ''. Need to add \' instead.
+ // 1st make sure we have our stringbuilder
+ if (result == null)
+ result = new StringBuilder(str, 0, i, str.Length * 2);
+
+ // Append a \' and keep going (so we don't turn off quote mode)
+ result.Append("\\'");
+ i++;
+ continue;
+ }
+
+ // Turning off quote mode, fall through to add it
+ inQuote = false;
+ }
+ else
+ {
+ // Found beginning quote, fall through to add it
+ inQuote = true;
+ }
+ }
+ // Is there a single \ character?
+ else if (str[i] == '\\')
+ {
+ // Found a \, need to change it to \\
+ // 1st make sure we have our stringbuilder
+ if (result == null)
+ result = new StringBuilder(str, 0, i, str.Length * 2);
+
+ // Append our \\ to the string & continue
+ result.Append("\\\\");
+ continue;
+ }
+
+ // If we have a builder we need to add our character
+ if (result != null)
+ result.Append(str[i]);
+ }
+
+ // Unchanged string? , just return input string
+ if (result == null)
+ return str;
+
+ // String changed, need to use the builder
+ return result.ToString();
+ }
+
+ internal static String[] ReescapeWin32Strings(String[] array)
+ {
+ if (array != null)
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = ReescapeWin32String(array[i]);
+ }
+ }
+
+ return array;
+ }
+
+ // If we get a group from windows, then its in 3;0 format with the 0 backwards
+ // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa)
+ // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning.
+ private static int[] ConvertWin32GroupString(String win32Str)
+ {
+ // None of these cases make any sense
+ if (win32Str == null || win32Str.Length == 0)
+ {
+ return (new int[] { 3 });
+ }
+
+ if (win32Str[0] == '0')
+ {
+ return (new int[] { 0 });
+ }
+
+ // Since its in n;n;n;n;n format, we can always get the length quickly
+ int[] values;
+ if (win32Str[win32Str.Length - 1] == '0')
+ {
+ // Trailing 0 gets dropped. 1;0 -> 1
+ values = new int[(win32Str.Length / 2)];
+ }
+ else
+ {
+ // Need extra space for trailing zero 1 -> 1;0
+ values = new int[(win32Str.Length / 2) + 2];
+ values[values.Length - 1] = 0;
+ }
+
+ int i;
+ int j;
+ for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
+ {
+ // Note that this # shouldn't ever be zero, 'cause 0 is only at end
+ // But we'll test because its registry that could be anything
+ if (win32Str[i] < '1' || win32Str[i] > '9')
+ return new int[] { 3 };
+
+ values[j] = (int)(win32Str[i] - '0');
+ }
+
+ return (values);
+ }
+
+ private static int ConvertFirstDayOfWeekMonToSun(int iTemp)
+ {
+ // Convert Mon-Sun to Sun-Sat format
+ iTemp++;
+ if (iTemp > 6)
+ {
+ // Wrap Sunday and convert invalid data to Sunday
+ iTemp = 0;
+ }
+ return iTemp;
+ }
+
+
+ // Context for EnumCalendarInfoExEx callback.
+ private class EnumLocaleData
+ {
+ public string regionName;
+ public string cultureName;
+ }
+
+ // EnumSystemLocaleEx callback.
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static unsafe Interop.BOOL EnumSystemLocalesProc(IntPtr lpLocaleString, uint flags, IntPtr contextHandle)
+ {
+ EnumLocaleData context = (EnumLocaleData)((GCHandle)contextHandle).Target;
+ try
+ {
+ string cultureName = new string((char*)lpLocaleString);
+ string regionName = Interop.mincore.GetLocaleInfoEx(cultureName, LOCALE_SISO3166CTRYNAME);
+ if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase))
+ {
+ context.cultureName = cultureName;
+ return Interop.BOOL.FALSE; // we found a match, then stop the enumeration
+ }
+
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ // Context for EnumTimeFormatsEx callback.
+ private class EnumData
+ {
+ public LowLevelList<string> strings;
+ }
+
+ // EnumTimeFormatsEx callback itself.
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static unsafe Interop.BOOL EnumTimeCallback(IntPtr lpTimeFormatString, IntPtr lParam)
+ {
+ EnumData context = (EnumData)((GCHandle)lParam).Target;
+
+ try
+ {
+ context.strings.Add(new string((char*)lpTimeFormatString));
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride)
+ {
+ const uint LOCALE_SSHORTTIME = 0x00000079;
+ const uint LOCALE_STIMEFORMAT = 0x00001003;
+
+ EnumData data = new EnumData();
+ data.strings = new LowLevelList<string>();
+
+ GCHandle dataHandle = GCHandle.Alloc(data);
+ try
+ {
+ // Now call the enumeration API. Work is done by our callback function
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, IntPtr, Interop.BOOL>>(EnumTimeCallback);
+ Interop.mincore.EnumTimeFormatsEx(callback, localeName, (uint)dwFlags, (IntPtr)dataHandle);
+ }
+ finally
+ {
+ dataHandle.Free();
+ }
+
+ if (data.strings.Count > 0)
+ {
+ // Now we need to allocate our stringarray and populate it
+ string[] results = data.strings.ToArray();
+
+ if (!useUserOverride && data.strings.Count > 1)
+ {
+ // Since there is no "NoUserOverride" aware EnumTimeFormatsEx, we always get an override
+ // The override is the first entry if it is overriden.
+ // We can check if we have overrides by checking the GetLocaleInfo with no override
+ // If we do have an override, we don't know if it is a user defined override or if the
+ // user has just selected one of the predefined formats so we can't just remove it
+ // but we can move it down.
+ uint lcType = (dwFlags == TIME_NOSECONDS) ? LOCALE_SSHORTTIME : LOCALE_STIMEFORMAT;
+ string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride);
+ if (timeFormatNoUserOverride != "")
+ {
+ string firstTimeFormat = results[0];
+ if (timeFormatNoUserOverride != firstTimeFormat)
+ {
+ results[0] = results[1];
+ results[1] = firstTimeFormat;
+ }
+ }
+ }
+
+ return results;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.cs b/src/mscorlib/corefx/System/Globalization/CultureData.cs
new file mode 100644
index 0000000000..eb71318fdb
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.cs
@@ -0,0 +1,2174 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using StringStringDictionary = Dictionary<string, string>;
+ using StringCultureDataDictionary = Dictionary<String, CultureData>;
+ using Lock = Object;
+#else
+ using StringStringDictionary = LowLevelDictionary<string, string>;
+ using StringCultureDataDictionary = LowLevelDictionary<string, CultureData>;
+#endif
+
+ //
+ // List of culture data
+ // Note the we cache overrides.
+ // Note that localized names (resource names) aren't available from here.
+ //
+
+ //
+ // Our names are a tad confusing.
+ //
+ // sWindowsName -- The name that windows thinks this culture is, ie:
+ // en-US if you pass in en-US
+ // de-DE_phoneb if you pass in de-DE_phoneb
+ // fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
+ // fj if you pass in fj (neutral, post-Windows 7 machine)
+ //
+ // sRealName -- The name you used to construct the culture, in pretty form
+ // en-US if you pass in EN-us
+ // en if you pass in en
+ // de-DE_phoneb if you pass in de-DE_phoneb
+ //
+ // sSpecificCulture -- The specific culture for this culture
+ // en-US for en-US
+ // en-US for en
+ // de-DE_phoneb for alt sort
+ // fj-FJ for fj (neutral)
+ //
+ // sName -- The IETF name of this culture (ie: no sort info, could be neutral)
+ // en-US if you pass in en-US
+ // en if you pass in en
+ // de-DE if you pass in de-DE_phoneb
+ //
+ internal partial class CultureData
+ {
+ private const int undef = -1;
+ private const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
+ private const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
+
+ // Override flag
+ private String _sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+ private String _sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+
+ // Identity
+ private String _sName; // locale name (ie: en-us, NO sort info, but could be neutral)
+ private String _sParent; // Parent name (which may be a custom locale/culture)
+ private String _sLocalizedDisplayName; // Localized pretty name for this locale
+ private String _sEnglishDisplayName; // English pretty name for this locale
+ private String _sNativeDisplayName; // Native pretty name for this locale
+ private String _sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
+
+ // Language
+ private String _sISO639Language; // ISO 639 Language Name
+ private String _sLocalizedLanguage; // Localized name for this language
+ private String _sEnglishLanguage; // English name for this language
+ private String _sNativeLanguage; // Native name of this language
+
+ // Region
+ private String _sRegionName; // (RegionInfo)
+ private String _sLocalizedCountry; // localized country name
+ private String _sEnglishCountry; // english country name (RegionInfo)
+ private String _sNativeCountry; // native country name
+ private String _sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
+
+ // Numbers
+ private String _sPositiveSign; // (user can override) positive sign
+ private String _sNegativeSign; // (user can override) negative sign
+ private String[] _saNativeDigits; // (user can override) native characters for digits 0-9
+ // (nfi populates these 5, don't have to be = undef)
+ private int _iDigits; // (user can override) number of fractional digits
+ private int _iNegativeNumber; // (user can override) negative number format
+ private int[] _waGrouping; // (user can override) grouping of digits
+ private String _sDecimalSeparator; // (user can override) decimal separator
+ private String _sThousandSeparator; // (user can override) thousands separator
+ private String _sNaN; // Not a Number
+ private String _sPositiveInfinity; // + Infinity
+ private String _sNegativeInfinity; // - Infinity
+
+ // Percent
+ private int _iNegativePercent = undef; // Negative Percent (0-3)
+ private int _iPositivePercent = undef; // Positive Percent (0-11)
+ private String _sPercent; // Percent (%) symbol
+ private String _sPerMille; // PerMille symbol
+
+ // Currency
+ private String _sCurrency; // (user can override) local monetary symbol
+ private String _sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
+ // (nfi populates these 4, don't have to be = undef)
+ private int _iCurrencyDigits; // (user can override) # local monetary fractional digits
+ private int _iCurrency; // (user can override) positive currency format
+ private int _iNegativeCurrency; // (user can override) negative currency format
+ private int[] _waMonetaryGrouping; // (user can override) monetary grouping of digits
+ private String _sMonetaryDecimal; // (user can override) monetary decimal separator
+ private String _sMonetaryThousand; // (user can override) monetary thousands separator
+
+ // Misc
+ private int _iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
+ private String _sListSeparator; // (user can override) list separator
+
+ // Time
+ private String _sAM1159; // (user can override) AM designator
+ private String _sPM2359; // (user can override) PM designator
+ private String _sTimeSeparator;
+ private volatile String[] _saLongTimes; // (user can override) time format
+ private volatile String[] _saShortTimes; // short time format
+ private volatile String[] _saDurationFormats; // time duration format
+
+ // Calendar specific data
+ private int _iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
+ private int _iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
+ private volatile CalendarId[] _waCalendars; // all available calendar type(s). The first one is the default calendar
+
+ // Store for specific data about each calendar
+ private CalendarData[] _calendars; // Store for specific calendar data
+
+ // Text information
+ private int _iReadingLayout = undef; // Reading layout data
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+
+ // CoreCLR depends on this even though its not exposed publicly.
+
+ private int _iLanguage; // locale ID (0409) - NO sort information
+ private bool _bUseOverrides; // use user overrides?
+ private bool _bNeutral; // Flags for the culture (ie: neutral or not right now)
+
+
+ // Region Name to Culture Name mapping table
+ // (In future would be nice to be in registry or something)
+
+ //Using a property so we avoid creating the dictionary untill we need it
+ private static StringStringDictionary RegionNames
+ {
+ get
+ {
+ if (s_RegionNames == null)
+ {
+ StringStringDictionary regionNames = new StringStringDictionary(211 /* prime */);
+
+ regionNames.Add("029", "en-029");
+ regionNames.Add("AE", "ar-AE");
+ regionNames.Add("AF", "prs-AF");
+ regionNames.Add("AL", "sq-AL");
+ regionNames.Add("AM", "hy-AM");
+ regionNames.Add("AR", "es-AR");
+ regionNames.Add("AT", "de-AT");
+ regionNames.Add("AU", "en-AU");
+ regionNames.Add("AZ", "az-Cyrl-AZ");
+ regionNames.Add("BA", "bs-Latn-BA");
+ regionNames.Add("BD", "bn-BD");
+ regionNames.Add("BE", "nl-BE");
+ regionNames.Add("BG", "bg-BG");
+ regionNames.Add("BH", "ar-BH");
+ regionNames.Add("BN", "ms-BN");
+ regionNames.Add("BO", "es-BO");
+ regionNames.Add("BR", "pt-BR");
+ regionNames.Add("BY", "be-BY");
+ regionNames.Add("BZ", "en-BZ");
+ regionNames.Add("CA", "en-CA");
+ regionNames.Add("CH", "it-CH");
+ regionNames.Add("CL", "es-CL");
+ regionNames.Add("CN", "zh-CN");
+ regionNames.Add("CO", "es-CO");
+ regionNames.Add("CR", "es-CR");
+ regionNames.Add("CS", "sr-Cyrl-CS");
+ regionNames.Add("CZ", "cs-CZ");
+ regionNames.Add("DE", "de-DE");
+ regionNames.Add("DK", "da-DK");
+ regionNames.Add("DO", "es-DO");
+ regionNames.Add("DZ", "ar-DZ");
+ regionNames.Add("EC", "es-EC");
+ regionNames.Add("EE", "et-EE");
+ regionNames.Add("EG", "ar-EG");
+ regionNames.Add("ES", "es-ES");
+ regionNames.Add("ET", "am-ET");
+ regionNames.Add("FI", "fi-FI");
+ regionNames.Add("FO", "fo-FO");
+ regionNames.Add("FR", "fr-FR");
+ regionNames.Add("GB", "en-GB");
+ regionNames.Add("GE", "ka-GE");
+ regionNames.Add("GL", "kl-GL");
+ regionNames.Add("GR", "el-GR");
+ regionNames.Add("GT", "es-GT");
+ regionNames.Add("HK", "zh-HK");
+ regionNames.Add("HN", "es-HN");
+ regionNames.Add("HR", "hr-HR");
+ regionNames.Add("HU", "hu-HU");
+ regionNames.Add("ID", "id-ID");
+ regionNames.Add("IE", "en-IE");
+ regionNames.Add("IL", "he-IL");
+ regionNames.Add("IN", "hi-IN");
+ regionNames.Add("IQ", "ar-IQ");
+ regionNames.Add("IR", "fa-IR");
+ regionNames.Add("IS", "is-IS");
+ regionNames.Add("IT", "it-IT");
+ regionNames.Add("IV", "");
+ regionNames.Add("JM", "en-JM");
+ regionNames.Add("JO", "ar-JO");
+ regionNames.Add("JP", "ja-JP");
+ regionNames.Add("KE", "sw-KE");
+ regionNames.Add("KG", "ky-KG");
+ regionNames.Add("KH", "km-KH");
+ regionNames.Add("KR", "ko-KR");
+ regionNames.Add("KW", "ar-KW");
+ regionNames.Add("KZ", "kk-KZ");
+ regionNames.Add("LA", "lo-LA");
+ regionNames.Add("LB", "ar-LB");
+ regionNames.Add("LI", "de-LI");
+ regionNames.Add("LK", "si-LK");
+ regionNames.Add("LT", "lt-LT");
+ regionNames.Add("LU", "lb-LU");
+ regionNames.Add("LV", "lv-LV");
+ regionNames.Add("LY", "ar-LY");
+ regionNames.Add("MA", "ar-MA");
+ regionNames.Add("MC", "fr-MC");
+ regionNames.Add("ME", "sr-Latn-ME");
+ regionNames.Add("MK", "mk-MK");
+ regionNames.Add("MN", "mn-MN");
+ regionNames.Add("MO", "zh-MO");
+ regionNames.Add("MT", "mt-MT");
+ regionNames.Add("MV", "dv-MV");
+ regionNames.Add("MX", "es-MX");
+ regionNames.Add("MY", "ms-MY");
+ regionNames.Add("NG", "ig-NG");
+ regionNames.Add("NI", "es-NI");
+ regionNames.Add("NL", "nl-NL");
+ regionNames.Add("NO", "nn-NO");
+ regionNames.Add("NP", "ne-NP");
+ regionNames.Add("NZ", "en-NZ");
+ regionNames.Add("OM", "ar-OM");
+ regionNames.Add("PA", "es-PA");
+ regionNames.Add("PE", "es-PE");
+ regionNames.Add("PH", "en-PH");
+ regionNames.Add("PK", "ur-PK");
+ regionNames.Add("PL", "pl-PL");
+ regionNames.Add("PR", "es-PR");
+ regionNames.Add("PT", "pt-PT");
+ regionNames.Add("PY", "es-PY");
+ regionNames.Add("QA", "ar-QA");
+ regionNames.Add("RO", "ro-RO");
+ regionNames.Add("RS", "sr-Latn-RS");
+ regionNames.Add("RU", "ru-RU");
+ regionNames.Add("RW", "rw-RW");
+ regionNames.Add("SA", "ar-SA");
+ regionNames.Add("SE", "sv-SE");
+ regionNames.Add("SG", "zh-SG");
+ regionNames.Add("SI", "sl-SI");
+ regionNames.Add("SK", "sk-SK");
+ regionNames.Add("SN", "wo-SN");
+ regionNames.Add("SV", "es-SV");
+ regionNames.Add("SY", "ar-SY");
+ regionNames.Add("TH", "th-TH");
+ regionNames.Add("TJ", "tg-Cyrl-TJ");
+ regionNames.Add("TM", "tk-TM");
+ regionNames.Add("TN", "ar-TN");
+ regionNames.Add("TR", "tr-TR");
+ regionNames.Add("TT", "en-TT");
+ regionNames.Add("TW", "zh-TW");
+ regionNames.Add("UA", "uk-UA");
+ regionNames.Add("US", "en-US");
+ regionNames.Add("UY", "es-UY");
+ regionNames.Add("UZ", "uz-Cyrl-UZ");
+ regionNames.Add("VE", "es-VE");
+ regionNames.Add("VN", "vi-VN");
+ regionNames.Add("YE", "ar-YE");
+ regionNames.Add("ZA", "af-ZA");
+ regionNames.Add("ZW", "en-ZW");
+
+ s_RegionNames = regionNames;
+ }
+
+ return s_RegionNames;
+ }
+ }
+
+ // Cache of regions we've already looked up
+ private static volatile StringCultureDataDictionary s_cachedRegions;
+ private static volatile StringStringDictionary s_RegionNames;
+
+ internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride)
+ {
+ // First do a shortcut for Invariant
+ if (String.IsNullOrEmpty(cultureName))
+ {
+ return CultureData.Invariant;
+ }
+
+ //
+ // First check if GetCultureData() can find it (ie: its a real culture)
+ //
+ CultureData retVal = GetCultureData(cultureName, useUserOverride);
+ if (retVal != null && (retVal.IsNeutralCulture == false)) return retVal;
+
+ //
+ // Not a specific culture, perhaps it's region-only name
+ // (Remember this isn't a core clr path where that's not supported)
+ //
+
+ // If it was neutral remember that so that RegionInfo() can throw the right exception
+ CultureData neutral = retVal;
+
+ // Try the hash table next
+ String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
+ StringCultureDataDictionary tempHashTable = s_cachedRegions;
+ if (tempHashTable == null)
+ {
+ // No table yet, make a new one
+ tempHashTable = new StringCultureDataDictionary();
+ }
+ else
+ {
+ // Check the hash table
+ lock (s_lock)
+ {
+ tempHashTable.TryGetValue(hashName, out retVal);
+ }
+ if (retVal != null)
+ {
+ return retVal;
+ }
+ }
+
+ //
+ // Not found in the hash table, look it up the hard way
+ //
+
+ // If not a valid mapping from the registry we'll have to try the hard coded table
+ if (retVal == null || (retVal.IsNeutralCulture == true))
+ {
+ // Not a valid mapping, try the hard coded table
+ string name;
+ if (RegionNames.TryGetValue(cultureName, out name))
+ {
+ // Make sure we can get culture data for it
+ retVal = GetCultureData(name, useUserOverride);
+ }
+ }
+
+ // If not found in the hard coded table we'll have to find a culture that works for us
+ if (retVal == null || (retVal.IsNeutralCulture == true))
+ {
+ retVal = GetCultureDataFromRegionName(cultureName);
+ }
+
+ // If we found one we can use, then cache it for next time
+ if (retVal != null && (retVal.IsNeutralCulture == false))
+ {
+ // first add it to the cache
+ lock (s_lock)
+ {
+ tempHashTable[hashName] = retVal;
+ }
+
+ // Copy the hashtable to the corresponding member variables. This will potentially overwrite
+ // new tables simultaneously created by a new thread, but maximizes thread safety.
+ s_cachedRegions = tempHashTable;
+ }
+ else
+ {
+ // Unable to find a matching culture/region, return null or neutral
+ // (regionInfo throws a more specific exception on neutrals)
+ retVal = neutral;
+ }
+
+ // Return the found culture to use, null, or the neutral culture.
+ return retVal;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////
+ // Build our invariant information
+ //
+ // We need an invariant instance, which we build hard-coded
+ /////////////////////////////////////////////////////////////////////////
+ internal static CultureData Invariant
+ {
+ get
+ {
+ if (s_Invariant == null)
+ {
+ // Make a new culturedata
+ CultureData invariant = new CultureData();
+
+ // Basics
+ // Note that we override the resources since this IS NOT supposed to change (by definition)
+ invariant._bUseOverrides = false;
+ invariant._sRealName = ""; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+ invariant._sWindowsName = ""; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+
+ // Identity
+ invariant._sName = ""; // locale name (ie: en-us)
+ invariant._sParent = ""; // Parent name (which may be a custom locale/culture)
+ invariant._bNeutral = false; // Flags for the culture (ie: neutral or not right now)
+ invariant._sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
+ invariant._sNativeDisplayName = "Invariant Language (Invariant Country)"; // Native pretty name for this locale
+ invariant._sSpecificCulture = ""; // The culture name to be used in CultureInfo.CreateSpecificCulture()
+
+ // Language
+ invariant._sISO639Language = "iv"; // ISO 639 Language Name
+ invariant._sLocalizedLanguage = "Invariant Language"; // Display name for this Language
+ invariant._sEnglishLanguage = "Invariant Language"; // English name for this language
+ invariant._sNativeLanguage = "Invariant Language"; // Native name of this language
+
+ // Region
+ invariant._sRegionName = "IV"; // (RegionInfo)
+ invariant._sEnglishCountry = "Invariant Country"; // english country name (RegionInfo)
+ invariant._sNativeCountry = "Invariant Country"; // native country name (Windows Only)
+ invariant._sISO3166CountryName = "IV"; // (RegionInfo), ie: US
+
+ // Numbers
+ invariant._sPositiveSign = "+"; // positive sign
+ invariant._sNegativeSign = "-"; // negative sign
+ invariant._saNativeDigits = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; // native characters for digits 0-9
+ invariant._iDigits = 2; // number of fractional digits
+ invariant._iNegativeNumber = 1; // negative number format
+ invariant._waGrouping = new int[] { 3 }; // grouping of digits
+ invariant._sDecimalSeparator = "."; // decimal separator
+ invariant._sThousandSeparator = ","; // thousands separator
+ invariant._sNaN = "NaN"; // Not a Number
+ invariant._sPositiveInfinity = "Infinity"; // + Infinity
+ invariant._sNegativeInfinity = "-Infinity"; // - Infinity
+
+ // Percent
+ invariant._iNegativePercent = 0; // Negative Percent (0-3)
+ invariant._iPositivePercent = 0; // Positive Percent (0-11)
+ invariant._sPercent = "%"; // Percent (%) symbol
+ invariant._sPerMille = "\x2030"; // PerMille symbol
+
+ // Currency
+ invariant._sCurrency = "\x00a4"; // local monetary symbol: for international monetary symbol
+ invariant._sIntlMonetarySymbol = "XDR"; // international monetary symbol (RegionInfo)
+ invariant._iCurrencyDigits = 2; // # local monetary fractional digits
+ invariant._iCurrency = 0; // positive currency format
+ invariant._iNegativeCurrency = 0; // negative currency format
+ invariant._waMonetaryGrouping = new int[] { 3 }; // monetary grouping of digits
+ invariant._sMonetaryDecimal = "."; // monetary decimal separator
+ invariant._sMonetaryThousand = ","; // monetary thousands separator
+
+ // Misc
+ invariant._iMeasure = 0; // system of measurement 0=metric, 1=US (RegionInfo)
+ invariant._sListSeparator = ","; // list separator
+
+ // Time
+ invariant._sAM1159 = "AM"; // AM designator
+ invariant._sPM2359 = "PM"; // PM designator
+ invariant._saLongTimes = new String[] { "HH:mm:ss" }; // time format
+ invariant._saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
+ invariant._saDurationFormats = new String[] { "HH:mm:ss" }; // time duration format
+
+
+ // Calendar specific data
+ invariant._iFirstDayOfWeek = 0; // first day of week
+ invariant._iFirstWeekOfYear = 0; // first week of year
+ invariant._waCalendars = new CalendarId[] { CalendarId.GREGORIAN }; // all available calendar type(s). The first one is the default calendar
+
+ // Store for specific data about each calendar
+ invariant._calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+ invariant._calendars[0] = CalendarData.Invariant;
+
+ // Text information
+ invariant._iReadingLayout = 0;
+
+ // These are desktop only, not coreclr
+
+ invariant._iLanguage = 0x007f; // locale ID (0409) - NO sort information
+ // Remember it
+ s_Invariant = invariant;
+ }
+ return s_Invariant;
+ }
+ }
+ private volatile static CultureData s_Invariant;
+
+ ///////////////
+ // Constructors //
+ ///////////////
+ // Cache of cultures we've already looked up
+ private static volatile StringCultureDataDictionary s_cachedCultures;
+ private static readonly Lock s_lock = new Lock();
+
+ internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
+ {
+ // First do a shortcut for Invariant
+ if (String.IsNullOrEmpty(cultureName))
+ {
+ return CultureData.Invariant;
+ }
+
+ // Try the hash table first
+ String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
+ StringCultureDataDictionary tempHashTable = s_cachedCultures;
+ if (tempHashTable == null)
+ {
+ // No table yet, make a new one
+ tempHashTable = new StringCultureDataDictionary();
+ }
+ else
+ {
+ // Check the hash table
+ bool ret;
+ CultureData retVal;
+ lock (s_lock)
+ {
+ ret = tempHashTable.TryGetValue(hashName, out retVal);
+ }
+ if (ret && retVal != null)
+ {
+ return retVal;
+ }
+ }
+
+ // Not found in the hash table, need to see if we can build one that works for us
+ CultureData culture = CreateCultureData(cultureName, useUserOverride);
+ if (culture == null)
+ {
+ return null;
+ }
+
+ // Found one, add it to the cache
+ lock (s_lock)
+ {
+ tempHashTable[hashName] = culture;
+ }
+
+ // Copy the hashtable to the corresponding member variables. This will potentially overwrite
+ // new tables simultaneously created by a new thread, but maximizes thread safety.
+ s_cachedCultures = tempHashTable;
+
+ return culture;
+ }
+
+ private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
+ {
+ CultureData culture = new CultureData();
+ culture._bUseOverrides = useUserOverride;
+ culture._sRealName = cultureName;
+
+ // Ask native code if that one's real
+ if (culture.InitCultureData() == false)
+ {
+ if (culture.InitCompatibilityCultureData() == false)
+ {
+ return null;
+ }
+ }
+
+ return culture;
+ }
+
+ private bool InitCompatibilityCultureData()
+ {
+ // for compatibility handle the deprecated ids: zh-chs, zh-cht
+ string cultureName = _sRealName;
+
+ string fallbackCultureName;
+ string realCultureName;
+ switch (AnsiToLower(cultureName))
+ {
+ case "zh-chs":
+ fallbackCultureName = "zh-Hans";
+ realCultureName = "zh-CHS";
+ break;
+ case "zh-cht":
+ fallbackCultureName = "zh-Hant";
+ realCultureName = "zh-CHT";
+ break;
+ default:
+ return false;
+ }
+
+ _sRealName = fallbackCultureName;
+ if (InitCultureData() == false)
+ {
+ return false;
+ }
+ // fixup our data
+ _sName = realCultureName; // the name that goes back to the user
+ _sParent = fallbackCultureName;
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // All the accessors
+ //
+ // Accessors for our data object items
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ ///////////
+ // Identity //
+ ///////////
+
+ // The real name used to construct the locale (ie: de-DE_phoneb)
+ internal String CultureName
+ {
+ get
+ {
+ Contract.Assert(_sRealName != null, "[CultureData.CultureName] Expected _sRealName to be populated by already");
+ // since windows doesn't know about zh-CHS and zh-CHT,
+ // we leave sRealName == zh-Hanx but we still need to
+ // pretend that it was zh-CHX.
+ switch (_sName)
+ {
+ case "zh-CHS":
+ case "zh-CHT":
+ return _sName;
+ }
+ return _sRealName;
+ }
+ }
+
+ // Are overrides enabled?
+ internal bool UseUserOverride
+ {
+ get
+ {
+ return _bUseOverrides;
+ }
+ }
+
+ // locale name (ie: de-DE, NO sort information)
+ internal String SNAME
+ {
+ get
+ {
+ if (_sName == null)
+ {
+ _sName = String.Empty;
+ }
+ return _sName;
+ }
+ }
+
+ // Parent name (which may be a custom locale/culture)
+ internal String SPARENT
+ {
+ get
+ {
+ if (_sParent == null)
+ {
+ // Ask using the real name, so that we get parents of neutrals
+ _sParent = GetLocaleInfo(_sRealName, LocaleStringData.ParentName);
+ }
+ return _sParent;
+ }
+ }
+
+ // Localized pretty name for this locale (ie: Inglis (estados Unitos))
+ internal String SLOCALIZEDDISPLAYNAME
+ {
+ get
+ {
+ if (_sLocalizedDisplayName == null)
+ {
+ if (this.IsSupplementalCustomCulture)
+ {
+ if (this.IsNeutralCulture)
+ {
+ _sLocalizedDisplayName = this.SNATIVELANGUAGE;
+ }
+ else
+ {
+ _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+ }
+ }
+ else
+ {
+ try
+ {
+ const string ZH_CHT = "zh-CHT";
+ const string ZH_CHS = "zh-CHS";
+
+ if (SNAME.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase))
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hant");
+ }
+ else if (SNAME.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase))
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hans");
+ }
+ else
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName(SNAME);
+ }
+ }
+ catch (Exception)
+ {
+ // do nothing
+ }
+ }
+ // If it hasn't been found (Windows 8 and up), fallback to the system
+ if (String.IsNullOrEmpty(_sLocalizedDisplayName))
+ {
+ // If its neutral use the language name
+ if (this.IsNeutralCulture)
+ {
+ _sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
+ }
+ else
+ {
+ // Usually the UI culture shouldn't be different than what we got from WinRT except
+ // if DefaultThreadCurrentUICulture was set
+ CultureInfo ci;
+
+ if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+ ((ci = GetUserDefaultCulture()) != null) &&
+ !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
+ {
+ _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+ }
+ else
+ {
+ _sLocalizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName);
+ }
+ }
+ }
+ }
+
+ return _sLocalizedDisplayName;
+ }
+ }
+
+ // English pretty name for this locale (ie: English (United States))
+ internal String SENGDISPLAYNAME
+ {
+ get
+ {
+ if (_sEnglishDisplayName == null)
+ {
+ // If its neutral use the language name
+ if (this.IsNeutralCulture)
+ {
+ _sEnglishDisplayName = this.SENGLISHLANGUAGE;
+ // differentiate the legacy display names
+ switch (_sName)
+ {
+ case "zh-CHS":
+ case "zh-CHT":
+ _sEnglishDisplayName += " Legacy";
+ break;
+ }
+ }
+ else
+ {
+ _sEnglishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName);
+
+ // if it isn't found build one:
+ if (String.IsNullOrEmpty(_sEnglishDisplayName))
+ {
+ // Our existing names mostly look like:
+ // "English" + "United States" -> "English (United States)"
+ // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
+ if (this.SENGLISHLANGUAGE[this.SENGLISHLANGUAGE.Length - 1] == ')')
+ {
+ // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
+ _sEnglishDisplayName =
+ this.SENGLISHLANGUAGE.Substring(0, _sEnglishLanguage.Length - 1) +
+ ", " + this.SENGCOUNTRY + ")";
+ }
+ else
+ {
+ // "English" + "United States" -> "English (United States)"
+ _sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
+ }
+ }
+ }
+ }
+ return _sEnglishDisplayName;
+ }
+ }
+
+ // Native pretty name for this locale (ie: Deutsch (Deutschland))
+ internal String SNATIVEDISPLAYNAME
+ {
+ get
+ {
+ if (_sNativeDisplayName == null)
+ {
+ // If its neutral use the language name
+ if (this.IsNeutralCulture)
+ {
+ _sNativeDisplayName = this.SNATIVELANGUAGE;
+ // differentiate the legacy display names
+ switch (_sName)
+ {
+ case "zh-CHS":
+ _sNativeDisplayName += " \u65E7\u7248";
+ break;
+ case "zh-CHT":
+ _sNativeDisplayName += " \u820A\u7248";
+ break;
+ }
+ }
+ else
+ {
+ _sNativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName);
+
+ // if it isn't found build one:
+ if (String.IsNullOrEmpty(_sNativeDisplayName))
+ {
+ // These should primarily be "Deutsch (Deutschland)" type names
+ _sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
+ }
+ }
+ }
+ return _sNativeDisplayName;
+ }
+ }
+
+ /////////////
+ // Language //
+ /////////////
+
+ // iso 639 language name, ie: en
+ internal String SISO639LANGNAME
+ {
+ get
+ {
+ if (_sISO639Language == null)
+ {
+ _sISO639Language = GetLocaleInfo(LocaleStringData.Iso639LanguageName);
+ }
+ return _sISO639Language;
+ }
+ }
+
+ // Localized name for this language (Windows Only) ie: Inglis
+ // This is only valid for Windows 8 and higher neutrals:
+ internal String SLOCALIZEDLANGUAGE
+ {
+ get
+ {
+ if (_sLocalizedLanguage == null)
+ {
+ // Usually the UI culture shouldn't be different than what we got from WinRT except
+ // if DefaultThreadCurrentUICulture was set
+ CultureInfo ci;
+
+ if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+ ((ci = GetUserDefaultCulture()) != null) &&
+ !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
+ {
+ _sLocalizedLanguage = SNATIVELANGUAGE;
+ }
+ else
+ {
+ _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName);
+ }
+ }
+
+ return _sLocalizedLanguage;
+ }
+ }
+
+ // English name for this language (Windows Only) ie: German
+ internal String SENGLISHLANGUAGE
+ {
+ get
+ {
+ if (_sEnglishLanguage == null)
+ {
+ _sEnglishLanguage = GetLocaleInfo(LocaleStringData.EnglishLanguageName);
+ }
+ return _sEnglishLanguage;
+ }
+ }
+
+ // Native name of this language (Windows Only) ie: Deutsch
+ internal String SNATIVELANGUAGE
+ {
+ get
+ {
+ if (_sNativeLanguage == null)
+ {
+ _sNativeLanguage = GetLocaleInfo(LocaleStringData.NativeLanguageName);
+ }
+ return _sNativeLanguage;
+ }
+ }
+
+ ///////////
+ // Region //
+ ///////////
+
+ // region name (eg US)
+ internal String SREGIONNAME
+ {
+ get
+ {
+ if (_sRegionName == null)
+ {
+ _sRegionName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
+ }
+ return _sRegionName;
+ }
+ }
+
+
+ // localized name for the country
+ internal string SLOCALIZEDCOUNTRY
+ {
+ get
+ {
+ if (_sLocalizedCountry == null)
+ {
+ try
+ {
+ _sLocalizedCountry = GetRegionDisplayName(SISO3166CTRYNAME);
+ }
+ catch (Exception)
+ {
+ // do nothing. we'll fallback
+ }
+
+ if (_sLocalizedCountry == null)
+ {
+ _sLocalizedCountry = SNATIVECOUNTRY;
+ }
+ }
+ return _sLocalizedCountry;
+ }
+ }
+
+ // english country name (RegionInfo) ie: Germany
+ internal String SENGCOUNTRY
+ {
+ get
+ {
+ if (_sEnglishCountry == null)
+ {
+ _sEnglishCountry = GetLocaleInfo(LocaleStringData.EnglishCountryName);
+ }
+ return _sEnglishCountry;
+ }
+ }
+
+ // native country name (RegionInfo) ie: Deutschland
+ internal String SNATIVECOUNTRY
+ {
+ get
+ {
+ if (_sNativeCountry == null)
+ {
+ _sNativeCountry = GetLocaleInfo(LocaleStringData.NativeCountryName);
+ }
+ return _sNativeCountry;
+ }
+ }
+
+ // ISO 3166 Country Name
+ internal String SISO3166CTRYNAME
+ {
+ get
+ {
+ if (_sISO3166CountryName == null)
+ {
+ _sISO3166CountryName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
+ }
+ return _sISO3166CountryName;
+ }
+ }
+
+ /////////////
+ // Numbers //
+ ////////////
+
+ // internal String sPositiveSign ; // (user can override) positive sign
+ // internal String sNegativeSign ; // (user can override) negative sign
+ // internal String[] saNativeDigits ; // (user can override) native characters for digits 0-9
+ // internal int iDigits ; // (user can override) number of fractional digits
+ // internal int iNegativeNumber ; // (user can override) negative number format
+
+
+
+ // (user can override) grouping of digits
+ internal int[] WAGROUPING
+ {
+ get
+ {
+ if (_waGrouping == null)
+ {
+ _waGrouping = GetLocaleInfo(LocaleGroupingData.Digit);
+ }
+ return _waGrouping;
+ }
+ }
+
+
+ // internal String sDecimalSeparator ; // (user can override) decimal separator
+ // internal String sThousandSeparator ; // (user can override) thousands separator
+
+ // Not a Number
+ internal String SNAN
+ {
+ get
+ {
+ if (_sNaN == null)
+ {
+ _sNaN = GetLocaleInfo(LocaleStringData.NaNSymbol);
+ }
+ return _sNaN;
+ }
+ }
+
+ // + Infinity
+ internal String SPOSINFINITY
+ {
+ get
+ {
+ if (_sPositiveInfinity == null)
+ {
+ _sPositiveInfinity = GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol);
+ }
+ return _sPositiveInfinity;
+ }
+ }
+
+ // - Infinity
+ internal String SNEGINFINITY
+ {
+ get
+ {
+ if (_sNegativeInfinity == null)
+ {
+ _sNegativeInfinity = GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol);
+ }
+ return _sNegativeInfinity;
+ }
+ }
+
+
+ ////////////
+ // Percent //
+ ///////////
+
+ // Negative Percent (0-3)
+ internal int INEGATIVEPERCENT
+ {
+ get
+ {
+ if (_iNegativePercent == undef)
+ {
+ // Note that <= Windows Vista this is synthesized by native code
+ _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat);
+ }
+ return _iNegativePercent;
+ }
+ }
+
+ // Positive Percent (0-11)
+ internal int IPOSITIVEPERCENT
+ {
+ get
+ {
+ if (_iPositivePercent == undef)
+ {
+ // Note that <= Windows Vista this is synthesized by native code
+ _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat);
+ }
+ return _iPositivePercent;
+ }
+ }
+
+ // Percent (%) symbol
+ internal String SPERCENT
+ {
+ get
+ {
+ if (_sPercent == null)
+ {
+ _sPercent = GetLocaleInfo(LocaleStringData.PercentSymbol);
+ }
+ return _sPercent;
+ }
+ }
+
+ // PerMille symbol
+ internal String SPERMILLE
+ {
+ get
+ {
+ if (_sPerMille == null)
+ {
+ _sPerMille = GetLocaleInfo(LocaleStringData.PerMilleSymbol);
+ }
+ return _sPerMille;
+ }
+ }
+
+ /////////////
+ // Currency //
+ /////////////
+
+ // (user can override) local monetary symbol, eg: $
+ internal String SCURRENCY
+ {
+ get
+ {
+ if (_sCurrency == null)
+ {
+ _sCurrency = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+ }
+ return _sCurrency;
+ }
+ }
+
+ // international monetary symbol (RegionInfo), eg: USD
+ internal String SINTLSYMBOL
+ {
+ get
+ {
+ if (_sIntlMonetarySymbol == null)
+ {
+ _sIntlMonetarySymbol = GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol);
+ }
+ return _sIntlMonetarySymbol;
+ }
+ }
+
+ // internal int iCurrencyDigits ; // (user can override) # local monetary fractional digits
+ // internal int iCurrency ; // (user can override) positive currency format
+ // internal int iNegativeCurrency ; // (user can override) negative currency format
+
+ // (user can override) monetary grouping of digits
+ internal int[] WAMONGROUPING
+ {
+ get
+ {
+ if (_waMonetaryGrouping == null)
+ {
+ _waMonetaryGrouping = GetLocaleInfo(LocaleGroupingData.Monetary);
+ }
+ return _waMonetaryGrouping;
+ }
+ }
+
+ // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
+ internal int IMEASURE
+ {
+ get
+ {
+ if (_iMeasure == undef)
+ {
+ _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem);
+ }
+ return _iMeasure;
+ }
+ }
+
+ // (user can override) list Separator
+ internal String SLIST
+ {
+ get
+ {
+ if (_sListSeparator == null)
+ {
+ _sListSeparator = GetLocaleInfo(LocaleStringData.ListSeparator);
+ }
+ return _sListSeparator;
+ }
+ }
+
+
+ ////////////////////////////
+ // Calendar/Time (Gregorian) //
+ ////////////////////////////
+
+ // (user can override) AM designator
+ internal String SAM1159
+ {
+ get
+ {
+ if (_sAM1159 == null)
+ {
+ _sAM1159 = GetLocaleInfo(LocaleStringData.AMDesignator);
+ }
+ return _sAM1159;
+ }
+ }
+
+ // (user can override) PM designator
+ internal String SPM2359
+ {
+ get
+ {
+ if (_sPM2359 == null)
+ {
+ _sPM2359 = GetLocaleInfo(LocaleStringData.PMDesignator);
+ }
+ return _sPM2359;
+ }
+ }
+
+ // (user can override) time format
+ internal String[] LongTimes
+ {
+ get
+ {
+ if (_saLongTimes == null)
+ {
+ String[] longTimes = GetTimeFormats();
+ if (longTimes == null || longTimes.Length == 0)
+ {
+ _saLongTimes = Invariant._saLongTimes;
+ }
+ else
+ {
+ _saLongTimes = longTimes;
+ }
+ }
+ return _saLongTimes;
+ }
+ }
+
+ // short time format
+ // Short times (derived from long times format)
+ // TODO: NLS Arrowhead - On Windows 7 we should have short times so this isn't necessary
+ internal String[] ShortTimes
+ {
+ get
+ {
+ if (_saShortTimes == null)
+ {
+ // Try to get the short times from the OS/culture.dll
+ String[] shortTimes = null;
+ shortTimes = GetShortTimeFormats();
+
+ if (shortTimes == null || shortTimes.Length == 0)
+ {
+ //
+ // If we couldn't find short times, then compute them from long times
+ // (eg: CORECLR on < Win7 OS & fallback for missing culture.dll)
+ //
+ shortTimes = DeriveShortTimesFromLong();
+ }
+
+ /* The above logic doesn't make sense on Mac, since the OS can provide us a "short time pattern".
+ * currently this is the 4th element in the array returned by LongTimes. We'll add this to our array
+ * if it doesn't exist.
+ */
+ shortTimes = AdjustShortTimesForMac(shortTimes);
+
+ // Found short times, use them
+ _saShortTimes = shortTimes;
+ }
+ return _saShortTimes;
+ }
+ }
+
+ private string[] AdjustShortTimesForMac(string[] shortTimes)
+ {
+ return shortTimes;
+ }
+
+ private string[] DeriveShortTimesFromLong()
+ {
+ // Our logic is to look for h,H,m,s,t. If we find an s, then we check the string
+ // between it and the previous marker, if any. If its a short, unescaped separator,
+ // then we don't retain that part.
+ // We then check after the ss and remove anything before the next h,H,m,t...
+ string[] shortTimes = new string[LongTimes.Length];
+
+ for (int i = 0; i < LongTimes.Length; i++)
+ {
+ shortTimes[i] = StripSecondsFromPattern(LongTimes[i]);
+ }
+ return shortTimes;
+ }
+
+ private static string StripSecondsFromPattern(string time)
+ {
+ bool bEscape = false;
+ int iLastToken = -1;
+
+ // Find the seconds
+ for (int j = 0; j < time.Length; j++)
+ {
+ // Change escape mode?
+ if (time[j] == '\'')
+ {
+ // Continue
+ bEscape = !bEscape;
+ continue;
+ }
+
+ // See if there was a single \
+ if (time[j] == '\\')
+ {
+ // Skip next char
+ j++;
+ continue;
+ }
+
+ if (bEscape)
+ {
+ continue;
+ }
+
+ switch (time[j])
+ {
+ // Check for seconds
+ case 's':
+ // Found seconds, see if there was something unescaped and short between
+ // the last marker and the seconds. Windows says separator can be a
+ // maximum of three characters (without null)
+ // If 1st or last characters were ', then ignore it
+ if ((j - iLastToken) <= 4 && (j - iLastToken) > 1 &&
+ (time[iLastToken + 1] != '\'') &&
+ (time[j - 1] != '\''))
+ {
+ // There was something there we want to remember
+ if (iLastToken >= 0)
+ {
+ j = iLastToken + 1;
+ }
+ }
+
+ bool containsSpace;
+ int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace);
+
+ string sep;
+
+ if (containsSpace)
+ {
+ sep = " ";
+ }
+ else
+ {
+ sep = "";
+ }
+
+ time = time.Substring(0, j) + sep + time.Substring(endIndex);
+ break;
+ case 'm':
+ case 'H':
+ case 'h':
+ iLastToken = j;
+ break;
+ }
+ }
+ return time;
+ }
+
+ private static int GetIndexOfNextTokenAfterSeconds(string time, int index, out bool containsSpace)
+ {
+ bool bEscape = false;
+ containsSpace = false;
+ for (; index < time.Length; index++)
+ {
+ switch (time[index])
+ {
+ case '\'':
+ bEscape = !bEscape;
+ continue;
+ case '\\':
+ index++;
+ if (time[index] == ' ')
+ {
+ containsSpace = true;
+ }
+ continue;
+ case ' ':
+ containsSpace = true;
+ break;
+ case 't':
+ case 'm':
+ case 'H':
+ case 'h':
+ if (bEscape)
+ {
+ continue;
+ }
+ return index;
+ }
+ }
+ containsSpace = false;
+ return index;
+ }
+
+ // (user can override) first day of week
+ internal int IFIRSTDAYOFWEEK
+ {
+ get
+ {
+ if (_iFirstDayOfWeek == undef)
+ {
+ _iFirstDayOfWeek = GetFirstDayOfWeek();
+ }
+ return _iFirstDayOfWeek;
+ }
+ }
+
+ // (user can override) first week of year
+ internal int IFIRSTWEEKOFYEAR
+ {
+ get
+ {
+ if (_iFirstWeekOfYear == undef)
+ {
+ _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear);
+ }
+ return _iFirstWeekOfYear;
+ }
+ }
+
+ // (user can override default only) short date format
+ internal String[] ShortDates(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saShortDates;
+ }
+
+ // (user can override default only) long date format
+ internal String[] LongDates(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saLongDates;
+ }
+
+ // (user can override) date year/month format.
+ internal String[] YearMonths(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saYearMonths;
+ }
+
+ // day names
+ internal string[] DayNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saDayNames;
+ }
+
+ // abbreviated day names
+ internal string[] AbbreviatedDayNames(CalendarId calendarId)
+ {
+ // Get abbreviated day names for this calendar from the OS if necessary
+ return GetCalendar(calendarId).saAbbrevDayNames;
+ }
+
+ // The super short day names
+ internal string[] SuperShortDayNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saSuperShortDayNames;
+ }
+
+ // month names
+ internal string[] MonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saMonthNames;
+ }
+
+ // Genitive month names
+ internal string[] GenitiveMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saMonthGenitiveNames;
+ }
+
+ // month names
+ internal string[] AbbreviatedMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saAbbrevMonthNames;
+ }
+
+ // Genitive month names
+ internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
+ }
+
+ // Leap year month names
+ // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name
+ // the non-leap names skip the 7th name in the normal month name array
+ internal string[] LeapYearMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saLeapYearMonthNames;
+ }
+
+ // month/day format (single string, no override)
+ internal String MonthDay(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).sMonthDay;
+ }
+
+
+
+ /////////////
+ // Calendars //
+ /////////////
+
+ // all available calendar type(s), The first one is the default calendar.
+ internal CalendarId[] CalendarIds
+ {
+ get
+ {
+ if (_waCalendars == null)
+ {
+ // We pass in an array of ints, and native side fills it up with count calendars.
+ // We then have to copy that list to a new array of the right size.
+ // Default calendar should be first
+ CalendarId[] calendars = new CalendarId[23];
+ Contract.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
+ int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars);
+
+ // See if we had a calendar to add.
+ if (count == 0)
+ {
+ // Failed for some reason, just grab Gregorian from Invariant
+ _waCalendars = Invariant._waCalendars;
+ }
+ else
+ {
+ // The OS may not return calendar 4 for zh-TW, but we've always allowed it.
+ // TODO: Is this hack necessary long-term?
+ if (_sWindowsName == "zh-TW")
+ {
+ bool found = false;
+
+ // Do we need to insert calendar 4?
+ for (int i = 0; i < count; i++)
+ {
+ // Stop if we found calendar four
+ if (calendars[i] == CalendarId.TAIWAN)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ // If not found then insert it
+ if (!found)
+ {
+ // Insert it as the 2nd calendar
+ count++;
+ // Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
+ Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1);
+ calendars[1] = CalendarId.TAIWAN;
+ }
+ }
+
+ // It worked, remember the list
+ CalendarId[] temp = new CalendarId[count];
+ Array.Copy(calendars, temp, count);
+
+ // Want 1st calendar to be default
+ // Prior to Vista the enumeration didn't have default calendar first
+ if (temp.Length > 1)
+ {
+ CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+ if (temp[1] == i)
+ {
+ temp[1] = temp[0];
+ temp[0] = i;
+ }
+ }
+
+ _waCalendars = temp;
+ }
+ }
+
+ return _waCalendars;
+ }
+ }
+
+ internal CalendarData GetCalendar(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0 && calendarId <= CalendarId.LAST_CALENDAR,
+ "[CultureData.GetCalendar] Expect calendarId to be in a valid range");
+
+ // arrays are 0 based, calendarIds are 1 based
+ int calendarIndex = (int)calendarId - 1;
+
+ // Have to have calendars
+ if (_calendars == null)
+ {
+ _calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+ }
+
+ // we need the following local variable to avoid returning null
+ // when another thread creates a new array of CalendarData (above)
+ // right after we insert the newly created CalendarData (below)
+ CalendarData calendarData = _calendars[calendarIndex];
+ // Make sure that calendar has data
+ if (calendarData == null)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already");
+ calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride);
+ _calendars[calendarIndex] = calendarData;
+ }
+
+ return calendarData;
+ }
+
+ ///////////////////
+ // Text Information //
+ ///////////////////
+
+ // IsRightToLeft
+ internal bool IsRightToLeft
+ {
+ get
+ {
+ // Returns one of the following 4 reading layout values:
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+ return (this.IREADINGLAYOUT == 1);
+ }
+ }
+
+ // IREADINGLAYOUT
+ // Returns one of the following 4 reading layout values:
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+ //
+ // If exposed as a public API, we'd have an enum with those 4 values
+ private int IREADINGLAYOUT
+ {
+ get
+ {
+ if (_iReadingLayout == undef)
+ {
+ Contract.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already");
+ _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout);
+ }
+
+ return (_iReadingLayout);
+ }
+ }
+
+ // The TextInfo name never includes that alternate sort and is always specific
+ // For customs, it uses the SortLocale (since the textinfo is not exposed in Win7)
+ // en -> en-US
+ // en-US -> en-US
+ // fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj)
+ // fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ)
+ // es-ES_tradnl -> es-ES
+ internal String STEXTINFO // Text info name to use for text information
+ {
+ get
+ {
+ // Note: Custom cultures might point at another culture's textinfo, however windows knows how
+ // to redirect it to the desired textinfo culture, so this is OK.
+ Contract.Assert(_sWindowsName != null, "[CultureData.STEXTINFO] Expected _sWindowsName to be populated by already");
+ return (_sWindowsName);
+ }
+ }
+
+ // Compare info name (including sorting key) to use if custom
+ internal String SCOMPAREINFO
+ {
+ get
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.SCOMPAREINFO] Expected _sWindowsName to be populated by already");
+ return (_sWindowsName);
+ }
+ }
+
+ internal bool IsSupplementalCustomCulture
+ {
+ get
+ {
+ return IsCustomCultureId(this.ILANGUAGE);
+ }
+ }
+
+ internal int ILANGUAGE
+ {
+ get
+ {
+ return _iLanguage;
+ }
+ }
+
+ internal bool IsNeutralCulture
+ {
+ get
+ {
+ // InitCultureData told us if we're neutral or not
+ return _bNeutral;
+ }
+ }
+
+ internal bool IsInvariantCulture
+ {
+ get
+ {
+ return String.IsNullOrEmpty(this.SNAME);
+ }
+ }
+
+ // Get an instance of our default calendar
+ internal Calendar DefaultCalendar
+ {
+ get
+ {
+ CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+
+ if (defaultCalId == 0)
+ {
+ defaultCalId = this.CalendarIds[0];
+ }
+
+ return CultureInfo.GetCalendarInstance(defaultCalId);
+ }
+ }
+
+ // All of our era names
+ internal String[] EraNames(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0");
+
+ return this.GetCalendar(calendarId).saEraNames;
+ }
+
+ internal String[] AbbrevEraNames(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
+
+ return this.GetCalendar(calendarId).saAbbrevEraNames;
+ }
+
+ internal String[] AbbreviatedEnglishEraNames(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
+
+ return this.GetCalendar(calendarId).saAbbrevEnglishEraNames;
+ }
+
+ //// String array DEFAULTS
+ //// Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
+
+
+ // Time separator (derived from time format)
+ internal String TimeSeparator
+ {
+ get
+ {
+ if (_sTimeSeparator == null)
+ {
+ string longTimeFormat = GetTimeFormatString();
+ if (String.IsNullOrEmpty(longTimeFormat))
+ {
+ longTimeFormat = LongTimes[0];
+ }
+
+ // Compute STIME from time format
+ _sTimeSeparator = GetTimeSeparator(longTimeFormat);
+ }
+ return _sTimeSeparator;
+ }
+ }
+
+ // Date separator (derived from short date format)
+ internal String DateSeparator(CalendarId calendarId)
+ {
+ return GetDateSeparator(ShortDates(calendarId)[0]);
+ }
+
+ //////////////////////////////////////
+ // Helper Functions to get derived properties //
+ //////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Unescape a NLS style quote string
+ //
+ // This removes single quotes:
+ // 'fred' -> fred
+ // 'fred -> fred
+ // fred' -> fred
+ // fred's -> freds
+ //
+ // This removes the first \ of escaped characters:
+ // fred\'s -> fred's
+ // a\\b -> a\b
+ // a\b -> ab
+ //
+ // We don't build the stringbuilder unless we find a ' or a \. If we find a ' or a \, we
+ // always build a stringbuilder because we need to remove the ' or \.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static String UnescapeNlsString(String str, int start, int end)
+ {
+ Contract.Requires(str != null);
+ Contract.Requires(start >= 0);
+ Contract.Requires(end >= 0);
+ StringBuilder result = null;
+
+ for (int i = start; i < str.Length && i <= end; i++)
+ {
+ switch (str[i])
+ {
+ case '\'':
+ if (result == null)
+ {
+ result = new StringBuilder(str, start, i - start, str.Length);
+ }
+ break;
+ case '\\':
+ if (result == null)
+ {
+ result = new StringBuilder(str, start, i - start, str.Length);
+ }
+ ++i;
+ if (i < str.Length)
+ {
+ result.Append(str[i]);
+ }
+ break;
+ default:
+ if (result != null)
+ {
+ result.Append(str[i]);
+ }
+ break;
+ }
+ }
+
+ if (result == null)
+ return (str.Substring(start, end - start + 1));
+
+ return (result.ToString());
+ }
+
+ private static String GetTimeSeparator(String format)
+ {
+ // Time format separator (ie: : in 12:39:00)
+ //
+ // We calculate this from the provided time format
+ //
+
+ //
+ // Find the time separator so that we can pretend we know STIME.
+ //
+ return GetSeparator(format, "Hhms");
+ }
+
+ private static String GetDateSeparator(String format)
+ {
+ // Date format separator (ie: / in 9/1/03)
+ //
+ // We calculate this from the provided short date
+ //
+
+ //
+ // Find the date separator so that we can pretend we know SDATE.
+ //
+ return GetSeparator(format, "dyM");
+ }
+
+ private static string GetSeparator(string format, string timeParts)
+ {
+ int index = IndexOfTimePart(format, 0, timeParts);
+
+ if (index != -1)
+ {
+ // Found a time part, find out when it changes
+ char cTimePart = format[index];
+
+ do
+ {
+ index++;
+ } while (index < format.Length && format[index] == cTimePart);
+
+ int separatorStart = index;
+
+ // Now we need to find the end of the separator
+ if (separatorStart < format.Length)
+ {
+ int separatorEnd = IndexOfTimePart(format, separatorStart, timeParts);
+ if (separatorEnd != -1)
+ {
+ // From [separatorStart, count) is our string, except we need to unescape
+ return UnescapeNlsString(format, separatorStart, separatorEnd - 1);
+ }
+ }
+ }
+
+ return String.Empty;
+ }
+
+ private static int IndexOfTimePart(string format, int startIndex, string timeParts)
+ {
+ Contract.Assert(startIndex >= 0, "startIndex cannot be negative");
+ Contract.Assert(timeParts.IndexOfAny(new char[] { '\'', '\\' }) == -1, "timeParts cannot include quote characters");
+ bool inQuote = false;
+ for (int i = startIndex; i < format.Length; ++i)
+ {
+ // See if we have a time Part
+ if (!inQuote && timeParts.IndexOf(format[i]) != -1)
+ {
+ return i;
+ }
+ switch (format[i])
+ {
+ case '\\':
+ if (i + 1 < format.Length)
+ {
+ ++i;
+ switch (format[i])
+ {
+ case '\'':
+ case '\\':
+ break;
+ default:
+ --i; //backup since we will move over this next
+ break;
+ }
+ }
+ break;
+ case '\'':
+ inQuote = !inQuote;
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ private static bool IsCustomCultureId(int cultureId)
+ {
+ return (cultureId == LOCALE_CUSTOM_DEFAULT || cultureId == LOCALE_CUSTOM_UNSPECIFIED);
+ }
+
+ internal void GetNFIValues(NumberFormatInfo nfi)
+ {
+ if (this.IsInvariantCulture)
+ {
+ // FUTURE: NumberFormatInfo already has default values for many of these fields. Can we not do this?
+ // if we do need to do this, then why don't we set nfi.nativeDigits in this case?
+ nfi.positiveSign = _sPositiveSign;
+ nfi.negativeSign = _sNegativeSign;
+
+ nfi.numberGroupSeparator = _sThousandSeparator;
+ nfi.numberDecimalSeparator = _sDecimalSeparator;
+ nfi.numberDecimalDigits = _iDigits;
+ nfi.numberNegativePattern = _iNegativeNumber;
+
+ nfi.currencySymbol = _sCurrency;
+ nfi.currencyGroupSeparator = _sMonetaryThousand;
+ nfi.currencyDecimalSeparator = _sMonetaryDecimal;
+ nfi.currencyDecimalDigits = _iCurrencyDigits;
+ nfi.currencyNegativePattern = _iNegativeCurrency;
+ nfi.currencyPositivePattern = _iCurrency;
+ }
+ else
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already");
+ // String values
+ nfi.positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign);
+ nfi.negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign);
+
+ nfi.numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator);
+ nfi.numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator);
+ nfi.currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator);
+ nfi.currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator);
+ nfi.currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+
+ // Numeric values
+ nfi.numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount);
+ nfi.currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount);
+ nfi.currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat);
+ nfi.currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat);
+ nfi.numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat);
+
+ // LOCALE_SNATIVEDIGITS (array of 10 single character strings).
+ string digits = GetLocaleInfo(LocaleStringData.Digits);
+ nfi.nativeDigits = new string[10];
+ for (int i = 0; i < nfi.nativeDigits.Length; i++)
+ {
+ nfi.nativeDigits[i] = new string(digits[i], 1);
+ }
+ }
+
+ //
+ // Gather additional data
+ //
+ nfi.numberGroupSizes = this.WAGROUPING;
+ nfi.currencyGroupSizes = this.WAMONGROUPING;
+
+ // prefer the cached value since these do not have user overrides
+ nfi.percentNegativePattern = this.INEGATIVEPERCENT;
+ nfi.percentPositivePattern = this.IPOSITIVEPERCENT;
+ nfi.percentSymbol = this.SPERCENT;
+ nfi.perMilleSymbol = this.SPERMILLE;
+
+ nfi.negativeInfinitySymbol = this.SNEGINFINITY;
+ nfi.positiveInfinitySymbol = this.SPOSINFINITY;
+ nfi.nanSymbol = this.SNAN;
+
+ //
+ // We don't have percent values, so use the number values
+ //
+ nfi.percentDecimalDigits = nfi.numberDecimalDigits;
+ nfi.percentDecimalSeparator = nfi.numberDecimalSeparator;
+ nfi.percentGroupSizes = nfi.numberGroupSizes;
+ nfi.percentGroupSeparator = nfi.numberGroupSeparator;
+
+ //
+ // Clean up a few odd values
+ //
+
+ // Windows usually returns an empty positive sign, but we like it to be "+"
+ if (nfi.positiveSign == null || nfi.positiveSign.Length == 0) nfi.positiveSign = "+";
+
+ //Special case for Italian. The currency decimal separator in the control panel is the empty string. When the user
+ //specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the
+ //decimal point doesn't show up. We'll just hack this here because our default currency format will never use nfi.
+ if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0)
+ {
+ nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator;
+ }
+ }
+
+ // Helper
+ // This is ONLY used for caching names and shouldn't be used for anything else
+ internal static string AnsiToLower(string testString)
+ {
+ StringBuilder sb = new StringBuilder(testString.Length);
+
+ for (int ich = 0; ich < testString.Length; ich++)
+ {
+ char ch = testString[ich];
+ sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
+ }
+
+ return (sb.ToString());
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleStringData : uint
+ {
+ /// <summary>localized name of locale, eg "German (Germany)" in UI language (coresponds to LOCALE_SLOCALIZEDDISPLAYNAME)</summary>
+ LocalizedDisplayName = 0x00000002,
+ /// <summary>Display name (language + country usually) in English, eg "German (Germany)" (coresponds to LOCALE_SENGLISHDISPLAYNAME)</summary>
+ EnglishDisplayName = 0x00000072,
+ /// <summary>Display name in native locale language, eg "Deutsch (Deutschland) (coresponds to LOCALE_SNATIVEDISPLAYNAME)</summary>
+ NativeDisplayName = 0x00000073,
+ /// <summary>Language Display Name for a language, eg "German" in UI language (coresponds to LOCALE_SLOCALIZEDLANGUAGENAME)</summary>
+ LocalizedLanguageName = 0x0000006f,
+ /// <summary>English name of language, eg "German" (coresponds to LOCALE_SENGLISHLANGUAGENAME)</summary>
+ EnglishLanguageName = 0x00001001,
+ /// <summary>native name of language, eg "Deutsch" (coresponds to LOCALE_SNATIVELANGUAGENAME)</summary>
+ NativeLanguageName = 0x00000004,
+ /// <summary>English name of country, eg "Germany" (coresponds to LOCALE_SENGLISHCOUNTRYNAME)</summary>
+ EnglishCountryName = 0x00001002,
+ /// <summary>native name of country, eg "Deutschland" (coresponds to LOCALE_SNATIVECOUNTRYNAME)</summary>
+ NativeCountryName = 0x00000008,
+ /// <summary>list item separator (coresponds to LOCALE_SLIST)</summary>
+ ListSeparator = 0x0000000C,
+ /// <summary>decimal separator (coresponds to LOCALE_SDECIMAL)</summary>
+ DecimalSeparator = 0x0000000E,
+ /// <summary>thousand separator (coresponds to LOCALE_STHOUSAND)</summary>
+ ThousandSeparator = 0x0000000F,
+ /// <summary>digit grouping (coresponds to LOCALE_SGROUPING)</summary>
+ Digits = 0x00000013,
+ /// <summary>local monetary symbol (coresponds to LOCALE_SCURRENCY)</summary>
+ MonetarySymbol = 0x00000014,
+ /// <summary>uintl monetary symbol (coresponds to LOCALE_SINTLSYMBOL)</summary>
+ Iso4217MonetarySymbol = 0x00000015,
+ /// <summary>monetary decimal separator (coresponds to LOCALE_SMONDECIMALSEP)</summary>
+ MonetaryDecimalSeparator = 0x00000016,
+ /// <summary>monetary thousand separator (coresponds to LOCALE_SMONTHOUSANDSEP)</summary>
+ MonetaryThousandSeparator = 0x00000017,
+ /// <summary>AM designator (coresponds to LOCALE_S1159)</summary>
+ AMDesignator = 0x00000028,
+ /// <summary>PM designator (coresponds to LOCALE_S2359)</summary>
+ PMDesignator = 0x00000029,
+ /// <summary>positive sign (coresponds to LOCALE_SPOSITIVESIGN)</summary>
+ PositiveSign = 0x00000050,
+ /// <summary>negative sign (coresponds to LOCALE_SNEGATIVESIGN)</summary>
+ NegativeSign = 0x00000051,
+ /// <summary>ISO abbreviated language name (coresponds to LOCALE_SISO639LANGNAME)</summary>
+ Iso639LanguageName = 0x00000059,
+ /// <summary>ISO abbreviated country name (coresponds to LOCALE_SISO3166CTRYNAME)</summary>
+ Iso3166CountryName = 0x0000005A,
+ /// <summary>Not a Number (coresponds to LOCALE_SNAN)</summary>
+ NaNSymbol = 0x00000069,
+ /// <summary>+ Infinity (coresponds to LOCALE_SPOSINFINITY)</summary>
+ PositiveInfinitySymbol = 0x0000006a,
+ /// <summary>- Infinity (coresponds to LOCALE_SNEGINFINITY)</summary>
+ NegativeInfinitySymbol = 0x0000006b,
+ /// <summary>Fallback name for resources (coresponds to LOCALE_SPARENT)</summary>
+ ParentName = 0x0000006d,
+ /// <summary>Returns the percent symbol (coresponds to LOCALE_SPERCENT)</summary>
+ PercentSymbol = 0x00000076,
+ /// <summary>Returns the permille (U+2030) symbol (coresponds to LOCALE_SPERMILLE)</summary>
+ PerMilleSymbol = 0x00000077
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleGroupingData : uint
+ {
+ /// <summary>digit grouping (coresponds to LOCALE_SGROUPING)</summary>
+ Digit = 0x00000010,
+ /// <summary>monetary grouping (coresponds to LOCALE_SMONGROUPING)</summary>
+ Monetary = 0x00000018,
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleNumberData : uint
+ {
+ /// <summary>language id (coresponds to LOCALE_ILANGUAGE)</summary>
+ LanguageId = 0x00000001,
+ /// <summary>0 = metric, 1 = US (coresponds to LOCALE_IMEASURE)</summary>
+ MeasurementSystem = 0x0000000D,
+ /// <summary>number of fractional digits (coresponds to LOCALE_IDIGITS)</summary>
+ FractionalDigitsCount = 0x00000011,
+ /// <summary>negative number mode (coresponds to LOCALE_INEGNUMBER)</summary>
+ NegativeNumberFormat = 0x00001010,
+ /// <summary># local monetary digits (coresponds to LOCALE_ICURRDIGITS)</summary>
+ MonetaryFractionalDigitsCount = 0x00000019,
+ /// <summary>positive currency mode (coresponds to LOCALE_ICURRENCY)</summary>
+ PositiveMonetaryNumberFormat = 0x0000001B,
+ /// <summary>negative currency mode (coresponds to LOCALE_INEGCURR)</summary>
+ NegativeMonetaryNumberFormat = 0x0000001C,
+ /// <summary>type of calendar specifier (coresponds to LOCALE_ICALENDARTYPE)</summary>
+ CalendarType = 0x00001009,
+ /// <summary>first day of week specifier (coresponds to LOCALE_IFIRSTDAYOFWEEK)</summary>
+ FirstDayOfWeek = 0x0000100C,
+ /// <summary>first week of year specifier (coresponds to LOCALE_IFIRSTWEEKOFYEAR)</summary>
+ FirstWeekOfYear = 0x0000100D,
+ /// <summary>
+ /// Returns one of the following 4 reading layout values:
+ /// 0 - Left to right (eg en-US)
+ /// 1 - Right to left (eg arabic locales)
+ /// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ /// 3 - Vertical top to bottom with columns proceeding to the right
+ /// (coresponds to LOCALE_IREADINGLAYOUT)
+ /// </summary>
+ ReadingLayout = 0x00000070,
+ /// <summary>Returns 0-11 for the negative percent format (coresponds to LOCALE_INEGATIVEPERCENT)</summary>
+ NegativePercentFormat = 0x00000074,
+ /// <summary>Returns 0-3 for the positive percent format (coresponds to LOCALE_IPOSITIVEPERCENT)</summary>
+ PositivePercentFormat = 0x00000075
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
new file mode 100644
index 0000000000..6911688b08
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Globalization
+{
+ public partial class CultureInfo : IFormatProvider
+ {
+ private static CultureInfo GetUserDefaultCultureCacheOverride()
+ {
+ return null; // ICU doesn't provide a user override
+ }
+
+ internal static CultureInfo GetUserDefaultCulture()
+ {
+ CultureInfo cultureInfo = null;
+ string localeName;
+ if (CultureData.GetDefaultLocaleName(out localeName))
+ {
+ cultureInfo = GetCultureByName(localeName, true);
+ cultureInfo.m_isReadOnly = true;
+ }
+ else
+ {
+ cultureInfo = CultureInfo.InvariantCulture;
+ }
+
+ return cultureInfo;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs
new file mode 100644
index 0000000000..16c8a06e08
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.Runtime.Augments;
+
+namespace System.Globalization
+{
+ public partial class CultureInfo : IFormatProvider
+ {
+ /// <summary>
+ /// Gets the default user culture from WinRT, if available.
+ /// </summary>
+ /// <remarks>
+ /// This method may return null, if there is no default user culture or if WinRT isn't available.
+ /// </remarks>
+ private static CultureInfo GetUserDefaultCultureCacheOverride()
+ {
+ WinRTInteropCallbacks callbacks = WinRTInterop.UnsafeCallbacks;
+ if (callbacks != null && callbacks.IsAppxModel())
+ {
+ return (CultureInfo)callbacks.GetUserDefaultCulture();
+ }
+
+ return null;
+ }
+
+ private static CultureInfo GetUserDefaultCulture()
+ {
+ const uint LOCALE_SNAME = 0x0000005c;
+ const string LOCALE_NAME_USER_DEFAULT = null;
+ const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale";
+
+ string strDefault = Interop.mincore.GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME);
+ if (strDefault == null)
+ {
+ strDefault = Interop.mincore.GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SNAME);
+
+ if (strDefault == null)
+ {
+ // If system default doesn't work, use invariant
+ return CultureInfo.InvariantCulture;
+ }
+ }
+
+ CultureInfo temp = GetCultureByName(strDefault, true);
+
+ temp._isReadOnly = true;
+
+ return temp;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
new file mode 100644
index 0000000000..f2b3742ab4
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
@@ -0,0 +1,1144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+//
+// Purpose: This class represents the software preferences of a particular
+// culture or community. It includes information such as the
+// language, writing system, and a calendar used by the culture
+// as well as methods for common operations such as printing
+// dates and sorting strings.
+//
+//
+//
+// !!!! NOTE WHEN CHANGING THIS CLASS !!!!
+//
+// If adding or removing members to this class, please update CultureInfoBaseObject
+// in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
+// different than the order in which members are declared. For instance, all
+// reference types will come first in the class before value types (like ints, bools, etc)
+// regardless of the order in which they are declared. The best way to see the
+// actual order of the class is to do a !dumpobj on an instance of the managed
+// object inside of the debugger.
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Threading;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using StringCultureInfoDictionary = Dictionary<string, CultureInfo>;
+ using Lock = Object;
+#else
+ using StringCultureInfoDictionary = LowLevelDictionary<string, CultureInfo>;
+#endif
+
+ [Serializable]
+ public partial class CultureInfo : IFormatProvider, ICloneable
+ {
+ //--------------------------------------------------------------------//
+ // Internal Information //
+ //--------------------------------------------------------------------//
+
+ //--------------------------------------------------------------------//
+ // Data members to be serialized:
+ //--------------------------------------------------------------------//
+
+ // We use an RFC4646 type string to construct CultureInfo.
+ // This string is stored in m_name and is authoritative.
+ // We use the m_cultureData to get the data for our object
+
+ private bool m_isReadOnly;
+ private CompareInfo compareInfo;
+ private TextInfo textInfo;
+ internal NumberFormatInfo numInfo;
+ internal DateTimeFormatInfo dateTimeInfo;
+ private Calendar calendar;
+ //
+ // The CultureData instance that we are going to read data from.
+ // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
+ // For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
+ //
+ [NonSerialized]
+ internal CultureData m_cultureData;
+
+ [NonSerialized]
+ internal bool m_isInherited;
+
+ // Names are confusing. Here are 3 names we have:
+ //
+ // new CultureInfo() m_name m_nonSortName m_sortName
+ // en-US en-US en-US en-US
+ // de-de_phoneb de-DE_phoneb de-DE de-DE_phoneb
+ // fj-fj (custom) fj-FJ fj-FJ en-US (if specified sort is en-US)
+ // en en
+ //
+ // Note that in Silverlight we ask the OS for the text and sort behavior, so the
+ // textinfo and compareinfo names are the same as the name
+
+ // Note that the name used to be serialized for Everett; it is now serialized
+ // because alernate sorts can have alternate names.
+ // This has a de-DE, de-DE_phoneb or fj-FJ style name
+ internal string m_name;
+
+ // This will hold the non sorting name to be returned from CultureInfo.Name property.
+ // This has a de-DE style name even for de-DE_phoneb type cultures
+ [NonSerialized]
+ private string m_nonSortName;
+
+ // This will hold the sorting name to be returned from CultureInfo.SortName property.
+ // This might be completely unrelated to the culture name if a custom culture. Ie en-US for fj-FJ.
+ // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
+ [NonSerialized]
+ private string m_sortName;
+
+
+ //--------------------------------------------------------------------//
+ //
+ // Static data members
+ //
+ //--------------------------------------------------------------------//
+
+ //Get the current user default culture. This one is almost always used, so we create it by default.
+ private static volatile CultureInfo s_userDefaultCulture;
+
+ //
+ // All of the following will be created on demand.
+ //
+
+ // WARNING: We allow diagnostic tools to directly inspect these three members (s_InvariantCultureInfo, s_DefaultThreadCurrentUICulture and s_DefaultThreadCurrentCulture)
+ // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details.
+ // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools.
+ // Get in touch with the diagnostics team if you have questions.
+
+ //The Invariant culture;
+ private static volatile CultureInfo s_InvariantCultureInfo;
+
+ //These are defaults that we use if a thread has not opted into having an explicit culture
+ private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
+ private static volatile CultureInfo s_DefaultThreadCurrentCulture;
+
+ [ThreadStatic]
+ private static volatile CultureInfo s_currentThreadCulture;
+ [ThreadStatic]
+ private static volatile CultureInfo s_currentThreadUICulture;
+
+ private static readonly Lock m_lock = new Lock();
+ private static volatile StringCultureInfoDictionary s_NameCachedCultures;
+
+ //The parent culture.
+ [NonSerialized]
+ private CultureInfo m_parent;
+
+ static AsyncLocal<CultureInfo> s_asyncLocalCurrentCulture;
+ static AsyncLocal<CultureInfo> s_asyncLocalCurrentUICulture;
+
+ static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
+ {
+ s_currentThreadCulture = args.CurrentValue;
+ }
+
+ static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
+ {
+ s_currentThreadUICulture = args.CurrentValue;
+ }
+
+ //
+ // The CultureData instance that reads the data provided by our CultureData class.
+ //
+ // Using a field initializer rather than a static constructor so that the whole class can be lazy
+ // init.
+ private static readonly bool init = Init();
+ private static bool Init()
+ {
+ if (s_InvariantCultureInfo == null)
+ {
+ CultureInfo temp = new CultureInfo("", false);
+ temp.m_isReadOnly = true;
+ s_InvariantCultureInfo = temp;
+ }
+
+ s_userDefaultCulture = GetUserDefaultCulture();
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CultureInfo Constructors
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public CultureInfo(String name)
+ : this(name, true)
+ {
+ }
+
+
+ internal CultureInfo(String name, bool useUserOverride)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name",
+ SR.ArgumentNull_String);
+ }
+
+ InitializeFromName(name, useUserOverride);
+ }
+
+ private void InitializeFromName(string name, bool useUserOverride)
+ {
+ // Get our data providing record
+ this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
+
+ if (this.m_cultureData == null)
+ {
+ throw new CultureNotFoundException("name", name, SR.Argument_CultureNotSupported);
+ }
+
+ this.m_name = this.m_cultureData.CultureName;
+ this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
+ }
+
+ // We do this to try to return the system UI language and the default user languages
+ // This method will fallback if this fails (like Invariant)
+ //
+ // TODO: It would appear that this is only ever called with userOveride = true
+ // and this method only has one caller. Can we fold it into the caller?
+ private static CultureInfo GetCultureByName(String name, bool userOverride)
+ {
+ CultureInfo ci = null;
+ // Try to get our culture
+ try
+ {
+ ci = userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
+ }
+ catch (ArgumentException)
+ {
+ }
+
+ if (ci == null)
+ {
+ ci = InvariantCulture;
+ }
+
+ return ci;
+ }
+
+ // //
+ // // Return a specific culture. A tad irrelevent now since we always return valid data
+ // // for neutral locales.
+ // //
+ // // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
+ // // if we can't find a bigger name. That doesn't help with things like "zh" though, so
+ // // the approach is of questionable value
+ // //
+
+ internal static bool VerifyCultureName(String cultureName, bool throwException)
+ {
+ // This function is used by ResourceManager.GetResourceFileName().
+ // ResourceManager searches for resource using CultureInfo.Name,
+ // so we should check against CultureInfo.Name.
+
+ for (int i = 0; i < cultureName.Length; i++)
+ {
+ char c = cultureName[i];
+ // TODO: Names can only be RFC4646 names (ie: a-zA-Z0-9) while this allows any unicode letter/digit
+ if (Char.IsLetterOrDigit(c) || c == '-' || c == '_')
+ {
+ continue;
+ }
+ if (throwException)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidResourceCultureName, cultureName));
+ }
+ return false;
+ }
+ return true;
+ }
+
+ internal static bool VerifyCultureName(CultureInfo culture, bool throwException)
+ {
+ //If we have an instance of one of our CultureInfos, the user can't have changed the
+ //name and we know that all names are valid in files.
+ if (!culture.m_isInherited)
+ {
+ return true;
+ }
+
+ return VerifyCultureName(culture.Name, throwException);
+ }
+
+ // We need to store the override from the culture data record.
+ private bool m_useUserOverride;
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx)
+ {
+ m_name = m_cultureData.CultureName;
+ m_useUserOverride = m_cultureData.UseUserOverride;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
+ InitializeFromName(m_name, m_useUserOverride);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CurrentCulture
+ //
+ // This instance provides methods based on the current user settings.
+ // These settings are volatile and may change over the lifetime of the
+ // thread.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ //
+ // We use the following order to return CurrentCulture and CurrentUICulture
+ // o Use WinRT to return the current user profile language
+ // o use current thread culture if the user already set one using CurrentCulture/CurrentUICulture
+ // o use thread culture if the user already set one using DefaultThreadCurrentCulture
+ // or DefaultThreadCurrentUICulture
+ // o Use NLS default user culture
+ // o Use NLS default system culture
+ // o Use Invariant culture
+ //
+ public static CultureInfo CurrentCulture
+ {
+ get
+ {
+ CultureInfo ci = GetUserDefaultCultureCacheOverride();
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ if (s_currentThreadCulture != null)
+ {
+ return s_currentThreadCulture;
+ }
+
+ ci = s_DefaultThreadCurrentCulture;
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ // if s_userDefaultCulture == null means CultureInfo statics didn't get initialized yet. this can happen if there early static
+ // method get executed which eventually hit the cultureInfo code while CultureInfo statics didn’t get chance to initialize
+ if (s_userDefaultCulture == null)
+ {
+ Init();
+ }
+
+ Contract.Assert(s_userDefaultCulture != null);
+ return s_userDefaultCulture;
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ if (s_asyncLocalCurrentCulture == null)
+ {
+ Interlocked.CompareExchange(ref s_asyncLocalCurrentCulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentCulture), null);
+ }
+ // this one will set s_currentThreadCulture too
+ s_asyncLocalCurrentCulture.Value = value;
+ }
+ }
+
+ public static CultureInfo CurrentUICulture
+ {
+ get
+ {
+ CultureInfo ci = GetUserDefaultCultureCacheOverride();
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ if (s_currentThreadUICulture != null)
+ {
+ return s_currentThreadUICulture;
+ }
+
+ ci = s_DefaultThreadCurrentUICulture;
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ // if s_userDefaultCulture == null means CultureInfo statics didn't get initialized yet. this can happen if there early static
+ // method get executed which eventually hit the cultureInfo code while CultureInfo statics didn’t get chance to initialize
+ if (s_userDefaultCulture == null)
+ {
+ Init();
+ }
+
+ Contract.Assert(s_userDefaultCulture != null);
+ return s_userDefaultCulture;
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ CultureInfo.VerifyCultureName(value, true);
+
+ if (s_asyncLocalCurrentUICulture == null)
+ {
+ Interlocked.CompareExchange(ref s_asyncLocalCurrentUICulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentUICulture), null);
+ }
+
+ // this one will set s_currentThreadUICulture too
+ s_asyncLocalCurrentUICulture.Value = value;
+ }
+ }
+
+ public static CultureInfo DefaultThreadCurrentCulture
+ {
+ get { return s_DefaultThreadCurrentCulture; }
+ set
+ {
+ // If you add pre-conditions to this method, check to see if you also need to
+ // add them to Thread.CurrentCulture.set.
+
+ s_DefaultThreadCurrentCulture = value;
+ }
+ }
+
+ public static CultureInfo DefaultThreadCurrentUICulture
+ {
+ get { return s_DefaultThreadCurrentUICulture; }
+ set
+ {
+ //If they're trying to use a Culture with a name that we can't use in resource lookup,
+ //don't even let them set it on the thread.
+
+ // If you add more pre-conditions to this method, check to see if you also need to
+ // add them to Thread.CurrentUICulture.set.
+
+ if (value != null)
+ {
+ CultureInfo.VerifyCultureName(value, true);
+ }
+
+ s_DefaultThreadCurrentUICulture = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // InvariantCulture
+ //
+ // This instance provides methods, for example for casing and sorting,
+ // that are independent of the system and current user settings. It
+ // should be used only by processes such as some system services that
+ // require such invariant results (eg. file systems). In general,
+ // the results are not linguistically correct and do not match any
+ // culture info.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public static CultureInfo InvariantCulture
+ {
+ get
+ {
+ return (s_InvariantCultureInfo);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Parent
+ //
+ // Return the parent CultureInfo for the current instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public virtual CultureInfo Parent
+ {
+ get
+ {
+ if (null == m_parent)
+ {
+ try
+ {
+ string parentName = this.m_cultureData.SPARENT;
+
+ if (String.IsNullOrEmpty(parentName))
+ {
+ m_parent = InvariantCulture;
+ }
+ else
+ {
+ m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride);
+ }
+ }
+ catch (ArgumentException)
+ {
+ // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
+ // We can't allow ourselves to fail. In case of custom cultures the parent of the
+ // current custom culture isn't installed.
+ m_parent = InvariantCulture;
+ }
+ }
+ return m_parent;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Name
+ //
+ // Returns the full name of the CultureInfo. The name is in format like
+ // "en-US" This version does NOT include sort information in the name.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String Name
+ {
+ get
+ {
+ // We return non sorting name here.
+ if (this.m_nonSortName == null)
+ {
+ this.m_nonSortName = this.m_cultureData.SNAME;
+ if (this.m_nonSortName == null)
+ {
+ this.m_nonSortName = String.Empty;
+ }
+ }
+ return this.m_nonSortName;
+ }
+ }
+
+ // This one has the sort information (ie: de-DE_phoneb)
+ internal String SortName
+ {
+ get
+ {
+ if (this.m_sortName == null)
+ {
+ this.m_sortName = this.m_cultureData.SCOMPAREINFO;
+ }
+
+ return this.m_sortName;
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // DisplayName
+ //
+ // Returns the full name of the CultureInfo in the localized language.
+ // For example, if the localized language of the runtime is Spanish and the CultureInfo is
+ // US English, "Ingles (Estados Unidos)" will be returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String DisplayName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ Contract.Assert(m_name != null, "[CultureInfo.DisplayName] Always expect m_name to be set");
+
+ return m_cultureData.SLOCALIZEDDISPLAYNAME;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetNativeName
+ //
+ // Returns the full name of the CultureInfo in the native language.
+ // For example, if the CultureInfo is US English, "English
+ // (United States)" will be returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String NativeName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SNATIVEDISPLAYNAME);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetEnglishName
+ //
+ // Returns the full name of the CultureInfo in English.
+ // For example, if the CultureInfo is US English, "English
+ // (United States)" will be returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String EnglishName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SENGDISPLAYNAME);
+ }
+ }
+
+ // ie: en
+ public virtual String TwoLetterISOLanguageName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SISO639LANGNAME);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CompareInfo Read-Only Property
+ //
+ // Gets the CompareInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual CompareInfo CompareInfo
+ {
+ get
+ {
+ if (this.compareInfo == null)
+ {
+ // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
+ // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
+ CompareInfo temp = UseUserOverride
+ ? GetCultureInfo(this.m_name).CompareInfo
+ : new CompareInfo(this);
+ if (OkayToCacheClassWithCompatibilityBehavior)
+ {
+ this.compareInfo = temp;
+ }
+ else
+ {
+ return temp;
+ }
+ }
+ return (compareInfo);
+ }
+ }
+
+ private static bool OkayToCacheClassWithCompatibilityBehavior
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // TextInfo
+ //
+ // Gets the TextInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual TextInfo TextInfo
+ {
+ get
+ {
+ if (textInfo == null)
+ {
+ // Make a new textInfo
+ TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
+ tempTextInfo.SetReadOnlyState(m_isReadOnly);
+
+ if (OkayToCacheClassWithCompatibilityBehavior)
+ {
+ textInfo = tempTextInfo;
+ }
+ else
+ {
+ return tempTextInfo;
+ }
+ }
+ return (textInfo);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Equals
+ //
+ // Implements Object.Equals(). Returns a boolean indicating whether
+ // or not object refers to the same CultureInfo as the current instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override bool Equals(Object value)
+ {
+ if (Object.ReferenceEquals(this, value))
+ return true;
+
+ CultureInfo that = value as CultureInfo;
+
+ if (that != null)
+ {
+ // using CompareInfo to verify the data passed through the constructor
+ // CultureInfo(String cultureName, String textAndCompareCultureName)
+
+ return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
+ }
+
+ return (false);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCode
+ //
+ // Implements Object.GetHashCode(). Returns the hash code for the
+ // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
+ // and B where A.Equals(B) is true.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public override int GetHashCode()
+ {
+ return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Implements Object.ToString(). Returns the name of the CultureInfo,
+ // eg. "de-DE_phoneb", "en-US", or "fj-FJ".
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override String ToString()
+ {
+ return m_name;
+ }
+
+
+ public virtual Object GetFormat(Type formatType)
+ {
+ if (formatType == typeof(NumberFormatInfo))
+ return (NumberFormat);
+ if (formatType == typeof(DateTimeFormatInfo))
+ return (DateTimeFormat);
+ return (null);
+ }
+
+ public virtual bool IsNeutralCulture
+ {
+ get
+ {
+ return this.m_cultureData.IsNeutralCulture;
+ }
+ }
+
+ public virtual NumberFormatInfo NumberFormat
+ {
+ get
+ {
+ if (numInfo == null)
+ {
+ NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
+ temp.isReadOnly = m_isReadOnly;
+ numInfo = temp;
+ }
+ return (numInfo);
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_Obj);
+ }
+ VerifyWritable();
+ numInfo = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetDateTimeFormatInfo
+ //
+ // Create a DateTimeFormatInfo, and fill in the properties according to
+ // the CultureID.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual DateTimeFormatInfo DateTimeFormat
+ {
+ get
+ {
+ if (dateTimeInfo == null)
+ {
+ // Change the calendar of DTFI to the specified calendar of this CultureInfo.
+ DateTimeFormatInfo temp = new DateTimeFormatInfo(this.m_cultureData, this.Calendar);
+ temp._isReadOnly = m_isReadOnly;
+ System.Threading.Interlocked.MemoryBarrier();
+ dateTimeInfo = temp;
+ }
+ return (dateTimeInfo);
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_Obj);
+ }
+ VerifyWritable();
+ dateTimeInfo = value;
+ }
+ }
+
+ /*=================================GetCalendarInstance==========================
+ **Action: Map a Win32 CALID to an instance of supported calendar.
+ **Returns: An instance of calendar.
+ **Arguments: calType The Win32 CALID
+ **Exceptions:
+ ** Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
+ ** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
+ ============================================================================*/
+ internal static Calendar GetCalendarInstance(CalendarId calType)
+ {
+ if (calType == CalendarId.GREGORIAN)
+ {
+ return (new GregorianCalendar());
+ }
+ return GetCalendarInstanceRare(calType);
+ }
+
+ //This function exists as a shortcut to prevent us from loading all of the non-gregorian
+ //calendars unless they're required.
+ internal static Calendar GetCalendarInstanceRare(CalendarId calType)
+ {
+ Contract.Assert(calType != CalendarId.GREGORIAN, "calType!=CalendarId.GREGORIAN");
+
+ switch (calType)
+ {
+ case CalendarId.GREGORIAN_US: // Gregorian (U.S.) calendar
+ case CalendarId.GREGORIAN_ME_FRENCH: // Gregorian Middle East French calendar
+ case CalendarId.GREGORIAN_ARABIC: // Gregorian Arabic calendar
+ case CalendarId.GREGORIAN_XLIT_ENGLISH: // Gregorian Transliterated English calendar
+ case CalendarId.GREGORIAN_XLIT_FRENCH: // Gregorian Transliterated French calendar
+ return (new GregorianCalendar((GregorianCalendarTypes)calType));
+ case CalendarId.TAIWAN: // Taiwan Era calendar
+ return (new TaiwanCalendar());
+ case CalendarId.JAPAN: // Japanese Emperor Era calendar
+ return (new JapaneseCalendar());
+ case CalendarId.KOREA: // Korean Tangun Era calendar
+ return (new KoreanCalendar());
+ case CalendarId.THAI: // Thai calendar
+ return (new ThaiBuddhistCalendar());
+ case CalendarId.HIJRI: // Hijri (Arabic Lunar) calendar
+ return (new HijriCalendar());
+ case CalendarId.HEBREW: // Hebrew (Lunar) calendar
+ return (new HebrewCalendar());
+ case CalendarId.UMALQURA:
+ return (new UmAlQuraCalendar());
+ case CalendarId.PERSIAN:
+ return (new PersianCalendar());
+ }
+ return (new GregorianCalendar());
+ }
+
+ /*=================================Calendar==========================
+ **Action: Return/set the default calendar used by this culture.
+ ** This value can be overridden by regional option if this is a current culture.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ** ArgumentNull_Obj if the set value is null.
+ ============================================================================*/
+ public virtual Calendar Calendar
+ {
+ get
+ {
+ if (calendar == null)
+ {
+ Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
+ // Get the default calendar for this culture. Note that the value can be
+ // from registry if this is a user default culture.
+ Calendar newObj = this.m_cultureData.DefaultCalendar;
+
+ System.Threading.Interlocked.MemoryBarrier();
+ newObj.SetReadOnlyState(m_isReadOnly);
+ calendar = newObj;
+ }
+ return (calendar);
+ }
+ }
+
+ /*=================================OptionCalendars==========================
+ **Action: Return an array of the optional calendar for this culture.
+ **Returns: an array of Calendar.
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+
+ public virtual Calendar[] OptionalCalendars
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<Calendar[]>() != null);
+
+ //
+ // This property always returns a new copy of the calendar array.
+ //
+ CalendarId[] calID = this.m_cultureData.CalendarIds;
+ Calendar[] cals = new Calendar[calID.Length];
+ for (int i = 0; i < cals.Length; i++)
+ {
+ cals[i] = GetCalendarInstance(calID[i]);
+ }
+ return (cals);
+ }
+ }
+
+
+ private bool UseUserOverride
+ {
+ get
+ {
+ return (this.m_cultureData.UseUserOverride);
+ }
+ }
+
+ public virtual Object Clone()
+ {
+ CultureInfo ci = (CultureInfo)MemberwiseClone();
+ ci.m_isReadOnly = false;
+
+ //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
+ //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
+ if (!m_isInherited)
+ {
+ if (this.dateTimeInfo != null)
+ {
+ ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
+ }
+ if (this.numInfo != null)
+ {
+ ci.numInfo = (NumberFormatInfo)this.numInfo.Clone();
+ }
+ }
+ else
+ {
+ ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
+ ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
+ }
+
+ if (textInfo != null)
+ {
+ ci.textInfo = (TextInfo)textInfo.Clone();
+ }
+
+ if (calendar != null)
+ {
+ ci.calendar = (Calendar)calendar.Clone();
+ }
+
+ return (ci);
+ }
+
+ public static CultureInfo ReadOnly(CultureInfo ci)
+ {
+ if (ci == null)
+ {
+ throw new ArgumentNullException("ci");
+ }
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ Contract.EndContractBlock();
+
+ if (ci.IsReadOnly)
+ {
+ return (ci);
+ }
+ CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
+
+ if (!ci.IsNeutralCulture)
+ {
+ //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
+ //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
+ if (!ci.m_isInherited)
+ {
+ if (ci.dateTimeInfo != null)
+ {
+ newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
+ }
+ if (ci.numInfo != null)
+ {
+ newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
+ }
+ }
+ else
+ {
+ newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
+ newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
+ }
+ }
+
+ if (ci.textInfo != null)
+ {
+ newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
+ }
+
+ if (ci.calendar != null)
+ {
+ newInfo.calendar = Calendar.ReadOnly(ci.calendar);
+ }
+
+ // Don't set the read-only flag too early.
+ // We should set the read-only flag here. Otherwise, info.DateTimeFormat will not be able to set.
+ newInfo.m_isReadOnly = true;
+
+ return (newInfo);
+ }
+
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return (m_isReadOnly);
+ }
+ }
+
+ private void VerifyWritable()
+ {
+ if (m_isReadOnly)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+ }
+
+ // For resource lookup, we consider a culture the invariant culture by name equality.
+ // We perform this check frequently during resource lookup, so adding a property for
+ // improved readability.
+ internal bool HasInvariantCultureName
+ {
+ get { return Name == CultureInfo.InvariantCulture.Name; }
+ }
+
+ // Helper function both both overloads of GetCachedReadOnlyCulture.
+ internal static CultureInfo GetCultureInfoHelper(string name)
+ {
+ // There is a race condition in this code with the side effect that the second thread's value
+ // clobbers the first in the dictionary. This is an acceptable race since the CultureInfo objects
+ // are content equal (but not reference equal). Since we make no guarantees there, this race is
+ // acceptable.
+
+ // retval is our return value.
+ CultureInfo retval;
+
+ if (name == null)
+ {
+ return null;
+ }
+
+ // Temporary hashtable for the names.
+ StringCultureInfoDictionary tempNameHT = s_NameCachedCultures;
+
+ name = CultureData.AnsiToLower(name);
+
+ // We expect the same result for both hashtables, but will test individually for added safety.
+ if (tempNameHT == null)
+ {
+ tempNameHT = new StringCultureInfoDictionary();
+ }
+ else
+ {
+ bool ret;
+ lock (m_lock)
+ {
+ ret = tempNameHT.TryGetValue(name, out retval);
+ }
+
+ if (ret && retval != null)
+ {
+ return retval;
+ }
+ }
+ try
+ {
+ retval = new CultureInfo(name, false);
+ }
+ catch (ArgumentException)
+ {
+ return null;
+ }
+
+ // Set it to read-only
+ retval.m_isReadOnly = true;
+
+ // Remember our name (as constructed). Do NOT use alternate sort name versions because
+ // we have internal state representing the sort. (So someone would get the wrong cached version)
+ string newName = CultureData.AnsiToLower(retval.m_name);
+
+ // We add this new culture info object to both tables.
+ lock (m_lock)
+ {
+ tempNameHT[newName] = retval;
+ }
+
+ s_NameCachedCultures = tempNameHT;
+
+ // Finally, return our new CultureInfo object.
+ return retval;
+ }
+
+ // Gets a cached copy of the specified culture from an internal hashtable (or creates it
+ // if not found). (Named version)
+ internal static CultureInfo GetCultureInfo(string name)
+ {
+ // Make sure we have a valid, non-zero length string as name
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ CultureInfo retval = GetCultureInfoHelper(name);
+ if (retval == null)
+ {
+ throw new CultureNotFoundException(
+ "name", name, SR.Argument_CultureNotSupported);
+ }
+ return retval;
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs b/src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs
new file mode 100644
index 0000000000..740063e4d3
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class CultureNotFoundException : ArgumentException, ISerializable
+ {
+ private string _invalidCultureName; // unrecognized culture name
+
+ public CultureNotFoundException()
+ : base(DefaultMessage)
+ {
+ }
+
+ public CultureNotFoundException(String message)
+ : base(message)
+ {
+ }
+
+ public CultureNotFoundException(String paramName, String message)
+ : base(message, paramName)
+ {
+ }
+
+ public CultureNotFoundException(String message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public CultureNotFoundException(String paramName, string invalidCultureName, String message)
+ : base(message, paramName)
+ {
+ _invalidCultureName = invalidCultureName;
+ }
+
+ public CultureNotFoundException(String message, string invalidCultureName, Exception innerException)
+ : base(message, innerException)
+ {
+ _invalidCultureName = invalidCultureName;
+ }
+
+ protected CultureNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ _invalidCultureName = (string)info.GetValue("InvalidCultureName", typeof(string));
+ }
+
+ [System.Security.SecurityCritical] // auto-generated_required
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException("info");
+ }
+
+ base.GetObjectData(info, context);
+ info.AddValue("InvalidCultureName", _invalidCultureName, typeof(string));
+ }
+
+ public virtual string InvalidCultureName
+ {
+ get { return _invalidCultureName; }
+ }
+
+ private static String DefaultMessage
+ {
+ get
+ {
+ return SR.Argument_CultureNotSupported;
+ }
+ }
+
+ private String FormatedInvalidCultureId
+ {
+ get
+ {
+ return InvalidCultureName;
+ }
+ }
+
+ public override String Message
+ {
+ get
+ {
+ String s = base.Message;
+ if (
+ _invalidCultureName != null)
+ {
+ String valueMessage = SR.Format(SR.Argument_CultureInvalidIdentifier, FormatedInvalidCultureId);
+ if (s == null)
+ return valueMessage;
+ return s + Environment.NewLine + valueMessage;
+ }
+ return s;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
new file mode 100644
index 0000000000..da746ada88
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
@@ -0,0 +1,2958 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Text;
+using System.Threading;
+
+namespace System.Globalization
+{
+ //
+ // Flags used to indicate different styles of month names.
+ // This is an internal flag used by internalGetMonthName().
+ // Use flag here in case that we need to provide a combination of these styles
+ // (such as month name of a leap year in genitive form. Not likely for now,
+ // but would like to keep the option open).
+ //
+
+ [Flags]
+ internal enum MonthNameStyles
+ {
+ Regular = 0x00000000,
+ Genitive = 0x00000001,
+ LeapYear = 0x00000002,
+ }
+
+ //
+ // Flags used to indicate special rule used in parsing/formatting
+ // for a specific DateTimeFormatInfo instance.
+ // This is an internal flag.
+ //
+ // This flag is different from MonthNameStyles because this flag
+ // can be expanded to accomodate parsing behaviors like CJK month names
+ // or alternative month names, etc.
+
+ [Flags]
+ internal enum DateTimeFormatFlags
+ {
+ None = 0x00000000,
+ UseGenitiveMonth = 0x00000001,
+ UseLeapYearMonth = 0x00000002,
+ UseSpacesInMonthNames = 0x00000004, // Has spaces or non-breaking space in the month names.
+ UseHebrewRule = 0x00000008, // Format/Parse using the Hebrew calendar rule.
+ UseSpacesInDayNames = 0x00000010, // Has spaces or non-breaking space in the day names.
+ UseDigitPrefixInTokens = 0x00000020, // Has token starting with numbers.
+
+ NotInitialized = -1,
+ }
+
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public sealed partial class DateTimeFormatInfo : IFormatProvider, ICloneable
+ {
+ // cache for the invariant culture.
+ // invariantInfo is constant irrespective of your current culture.
+ private static volatile DateTimeFormatInfo s_invariantInfo;
+
+ // an index which points to a record in Culture Data Table.
+ [NonSerialized]
+ private CultureData _cultureData;
+
+ // The culture name used to create this DTFI.
+
+ [OptionalField(VersionAdded = 2)]
+ private String _name = null;
+
+ // The language name of the culture used to create this DTFI.
+ [NonSerialized]
+ private String _langName = null;
+
+ // CompareInfo usually used by the parser.
+ [NonSerialized]
+ private CompareInfo _compareInfo = null;
+
+ // Culture matches current DTFI. mainly used for string comparisons during parsing.
+ [NonSerialized]
+ private CultureInfo _cultureInfo = null;
+
+ //
+ // Caches for various properties.
+ //
+
+ private String amDesignator = null;
+ private String pmDesignator = null;
+
+ private String dateSeparator = null; // derived from short date (whidbey expects, arrowhead doesn't)
+
+ private String generalShortTimePattern = null; // short date + short time (whidbey expects, arrowhead doesn't)
+
+ private String generalLongTimePattern = null; // short date + long time (whidbey expects, arrowhead doesn't)
+
+ private String timeSeparator = null; // derived from long time (whidbey expects, arrowhead doesn't)
+ private String monthDayPattern = null;
+ // added in .NET Framework Release {2.0SP1/3.0SP1/3.5RTM}
+ private String dateTimeOffsetPattern = null;
+
+ //
+ // The following are constant values.
+ //
+ private const String rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
+
+ // The sortable pattern is based on ISO 8601.
+ private const String sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
+ private const String universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
+
+ //
+ // The following are affected by calendar settings.
+ //
+ private Calendar calendar = null;
+
+ private int firstDayOfWeek = -1;
+ private int calendarWeekRule = -1;
+
+
+ private String fullDateTimePattern = null; // long date + long time (whidbey expects, arrowhead doesn't)
+
+ private String[] abbreviatedDayNames = null;
+
+
+ private String[] m_superShortDayNames = null;
+
+ private String[] dayNames = null;
+ private String[] abbreviatedMonthNames = null;
+ private String[] monthNames = null;
+ // Cache the genitive month names that we retrieve from the data table.
+
+ private String[] genitiveMonthNames = null;
+
+ // Cache the abbreviated genitive month names that we retrieve from the data table.
+
+ private String[] m_genitiveAbbreviatedMonthNames = null;
+
+ // Cache the month names of a leap year that we retrieve from the data table.
+
+ private String[] leapYearMonthNames = null;
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+
+ // The "default" Date/time patterns
+ private String longDatePattern = null;
+ private String shortDatePattern = null;
+ private String yearMonthPattern = null;
+ private String longTimePattern = null;
+ private String shortTimePattern = null;
+
+ [OptionalField(VersionAdded = 3)]
+ private String[] allYearMonthPatterns = null;
+
+ private String[] allShortDatePatterns = null;
+ private String[] allLongDatePatterns = null;
+ private String[] allShortTimePatterns = null;
+ private String[] allLongTimePatterns = null;
+
+ // Cache the era names for this DateTimeFormatInfo instance.
+ private String[] m_eraNames = null;
+ private String[] m_abbrevEraNames = null;
+ private String[] m_abbrevEnglishEraNames = null;
+
+ private CalendarId[] optionalCalendars = null;
+
+ private const int DEFAULT_ALL_DATETIMES_SIZE = 132;
+
+ // CultureInfo updates this
+ internal bool _isReadOnly = false;
+
+ // This flag gives hints about if formatting/parsing should perform special code path for things like
+ // genitive form or leap year month names.
+
+ private DateTimeFormatFlags formatFlags = DateTimeFormatFlags.NotInitialized;
+
+ private String CultureName
+ {
+ get
+ {
+ if (_name == null)
+ {
+ _name = _cultureData.CultureName;
+ }
+ return (_name);
+ }
+ }
+
+ private CultureInfo Culture
+ {
+ get
+ {
+ if (_cultureInfo == null)
+ {
+ _cultureInfo = CultureInfo.GetCultureInfo(this.CultureName);
+ }
+ return _cultureInfo;
+ }
+ }
+
+ // TODO: This ignores other cultures that might want to do something similar
+ private String LanguageName
+ {
+ get
+ {
+ if (_langName == null)
+ {
+ _langName = _cultureData.SISO639LANGNAME;
+ }
+ return (_langName);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the abbreviated day names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetAbbreviatedDayOfWeekNames()
+ {
+ if (this.abbreviatedDayNames == null)
+ {
+ // Get the abbreviated day names for our current calendar
+ this.abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID);
+ Contract.Assert(this.abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week");
+ }
+ return (this.abbreviatedDayNames);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Action: Returns the string array of the one-letter day of week names.
+ // Returns:
+ // an array of one-letter day of week names
+ // Arguments:
+ // None
+ // Exceptions:
+ // None
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetSuperShortDayNames()
+ {
+ if (this.m_superShortDayNames == null)
+ {
+ // Get the super short day names for our current calendar
+ this.m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID);
+ Contract.Assert(this.m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected 7 day names in a week");
+ }
+ return (this.m_superShortDayNames);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the day names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetDayOfWeekNames()
+ {
+ if (this.dayNames == null)
+ {
+ // Get the day names for our current calendar
+ this.dayNames = _cultureData.DayNames(Calendar.ID);
+ Contract.Assert(this.dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week");
+ }
+ return (this.dayNames);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the abbreviated month names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetAbbreviatedMonthNames()
+ {
+ if (this.abbreviatedMonthNames == null)
+ {
+ // Get the month names for our current calendar
+ this.abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID);
+ Contract.Assert(this.abbreviatedMonthNames.Length == 12 || this.abbreviatedMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year");
+ }
+ return (this.abbreviatedMonthNames);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the month names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetMonthNames()
+ {
+ if (this.monthNames == null)
+ {
+ // Get the month names for our current calendar
+ this.monthNames = _cultureData.MonthNames(Calendar.ID);
+ Contract.Assert(this.monthNames.Length == 12 || this.monthNames.Length == 13,
+ "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year");
+ }
+
+ return (this.monthNames);
+ }
+
+
+ //
+ // Invariant DateTimeFormatInfo doesn't have user-overriden values
+ // Default calendar is gregorian
+ public DateTimeFormatInfo()
+ : this(CultureInfo.InvariantCulture.m_cultureData,
+ GregorianCalendar.GetDefaultInstance())
+ {
+ }
+
+ internal DateTimeFormatInfo(CultureData cultureData, Calendar cal)
+ {
+ Contract.Requires(cultureData != null);
+ Contract.Requires(cal != null);
+
+ // Remember our culture
+ _cultureData = cultureData;
+
+ this.Calendar = cal;
+ }
+
+ private void InitializeOverridableProperties(CultureData cultureData, CalendarId calendarId)
+ {
+ Contract.Requires(cultureData != null);
+ Contract.Assert(calendarId != CalendarId.UNINITIALIZED_VALUE, "[DateTimeFormatInfo.Populate] Expected initalized calendarId");
+
+ if (this.firstDayOfWeek == -1) { this.firstDayOfWeek = cultureData.IFIRSTDAYOFWEEK; }
+ if (this.calendarWeekRule == -1) { this.calendarWeekRule = cultureData.IFIRSTWEEKOFYEAR; }
+
+ if (this.amDesignator == null) { this.amDesignator = cultureData.SAM1159; }
+ if (this.pmDesignator == null) { this.pmDesignator = cultureData.SPM2359; }
+ if (this.timeSeparator == null) { this.timeSeparator = cultureData.TimeSeparator; }
+ if (this.dateSeparator == null) { this.dateSeparator = cultureData.DateSeparator(calendarId); }
+
+ this.allLongTimePatterns = _cultureData.LongTimes;
+ Contract.Assert(this.allLongTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long time patterns");
+
+ this.allShortTimePatterns = _cultureData.ShortTimes;
+ Contract.Assert(this.allShortTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short time patterns");
+
+ this.allLongDatePatterns = cultureData.LongDates(calendarId);
+ Contract.Assert(this.allLongDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long date patterns");
+
+ this.allShortDatePatterns = cultureData.ShortDates(calendarId);
+ Contract.Assert(this.allShortDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short date patterns");
+
+ this.allYearMonthPatterns = cultureData.YearMonths(calendarId);
+ Contract.Assert(this.allYearMonthPatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some year month patterns");
+ }
+
+ [OptionalField(VersionAdded = 1)]
+ private bool _useUserOverride;
+
+ // This was synthesized by Whidbey so we knew what words might appear in the middle of a date string
+ // Now we always synthesize so its not helpful
+
+ internal String[] m_dateWords = null;
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx)
+ {
+ _name = this.CultureName; // make sure the _name is initialized.
+ _useUserOverride = _cultureData.UseUserOverride;
+
+ // Important to initialize these fields otherwise we may run into exception when deserializing on Whidbey
+ // because Whidbey try to initialize some of these fields using calendar data which could be null values
+ // and then we get exceptions. So we call the accessors to force the caches to get loaded.
+ Object o;
+ o = this.LongTimePattern;
+ o = this.LongDatePattern;
+ o = this.ShortTimePattern;
+ o = this.ShortDatePattern;
+ o = this.YearMonthPattern;
+ o = this.AllLongTimePatterns;
+ o = this.AllLongDatePatterns;
+ o = this.AllShortTimePatterns;
+ o = this.AllShortDatePatterns;
+ o = this.AllYearMonthPatterns;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ if (_name != null)
+ {
+ _cultureData = CultureData.GetCultureData(_name, _useUserOverride);
+ if (_cultureData == null)
+ {
+ throw new CultureNotFoundException("_name", _name, SR.Argument_CultureNotSupported);
+ }
+ }
+
+ if (calendar == null)
+ {
+ calendar = (Calendar)GregorianCalendar.GetDefaultInstance().Clone();
+ calendar.SetReadOnlyState(_isReadOnly);
+ }
+
+ InitializeOverridableProperties(_cultureData, calendar.ID);
+
+ //
+ // turn off read only state till we finish initializing all fields and then store read only state after we are done.
+ //
+ bool isReadOnly = _isReadOnly;
+ _isReadOnly = false;
+
+ // If we deserialized defaults ala Whidbey, make sure they're still defaults
+ // Whidbey's arrays could get a bit mixed up.
+ if (longDatePattern != null) this.LongDatePattern = longDatePattern;
+ if (shortDatePattern != null) this.ShortDatePattern = shortDatePattern;
+ if (yearMonthPattern != null) this.YearMonthPattern = yearMonthPattern;
+ if (longTimePattern != null) this.LongTimePattern = longTimePattern;
+ if (shortTimePattern != null) this.ShortTimePattern = shortTimePattern;
+
+ _isReadOnly = isReadOnly;
+ }
+
+ // Returns a default DateTimeFormatInfo that will be universally
+ // supported and constant irrespective of the current culture.
+ // Used by FromString methods.
+ //
+
+ public static DateTimeFormatInfo InvariantInfo
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
+ if (s_invariantInfo == null)
+ {
+ DateTimeFormatInfo info = new DateTimeFormatInfo();
+ info.Calendar.SetReadOnlyState(true);
+ info._isReadOnly = true;
+ s_invariantInfo = info;
+ }
+ return (s_invariantInfo);
+ }
+ }
+
+ // Returns the current culture's DateTimeFormatInfo. Used by Parse methods.
+ //
+
+ public static DateTimeFormatInfo CurrentInfo
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
+ System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;
+ if (!culture.m_isInherited)
+ {
+ DateTimeFormatInfo info = culture.dateTimeInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ }
+ return (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo));
+ }
+ }
+
+
+ public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
+ {
+ // Fast case for a regular CultureInfo
+ DateTimeFormatInfo info;
+ CultureInfo cultureProvider = provider as CultureInfo;
+ if (cultureProvider != null && !cultureProvider.m_isInherited)
+ {
+ return cultureProvider.DateTimeFormat;
+ }
+ // Fast case for a DTFI;
+ info = provider as DateTimeFormatInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ // Wasn't cultureInfo or DTFI, do it the slower way
+ if (provider != null)
+ {
+ info = provider.GetFormat(typeof(DateTimeFormatInfo)) as DateTimeFormatInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ }
+ // Couldn't get anything, just use currentInfo as fallback
+ return CurrentInfo;
+ }
+
+
+ public Object GetFormat(Type formatType)
+ {
+ return (formatType == typeof(DateTimeFormatInfo) ? this : null);
+ }
+
+
+ public Object Clone()
+ {
+ DateTimeFormatInfo n = (DateTimeFormatInfo)MemberwiseClone();
+ // We can use the data member calendar in the setter, instead of the property Calendar,
+ // since the cloned copy should have the same state as the original copy.
+ n.calendar = (Calendar)this.Calendar.Clone();
+ n._isReadOnly = false;
+ return n;
+ }
+
+
+ public String AMDesignator
+ {
+ // auto-generated
+ get
+ {
+ if (this.amDesignator == null)
+ {
+ this.amDesignator = _cultureData.SAM1159;
+ }
+ Contract.Assert(this.amDesignator != null, "DateTimeFormatInfo.AMDesignator, amDesignator != null");
+ return (this.amDesignator);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ ClearTokenHashTable();
+ amDesignator = value;
+ }
+ }
+
+
+ public Calendar Calendar
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<Calendar>() != null);
+
+ Contract.Assert(this.calendar != null, "DateTimeFormatInfo.Calendar: calendar != null");
+ return (this.calendar);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ if (value == calendar)
+ {
+ return;
+ }
+
+ for (int i = 0; i < this.OptionalCalendars.Length; i++)
+ {
+ if (this.OptionalCalendars[i] == value.ID)
+ {
+ // We can use this one, so do so.
+
+ // Clean related properties if we already had a calendar set
+ if (calendar != null)
+ {
+ // clean related properties which are affected by the calendar setting,
+ // so that they will be refreshed when they are accessed next time.
+ //
+
+ // These properites are in the order as appearing in calendar.xml.
+ m_eraNames = null;
+ m_abbrevEraNames = null;
+ m_abbrevEnglishEraNames = null;
+
+ monthDayPattern = null;
+
+ dayNames = null;
+ abbreviatedDayNames = null;
+ m_superShortDayNames = null;
+ monthNames = null;
+ abbreviatedMonthNames = null;
+ genitiveMonthNames = null;
+ m_genitiveAbbreviatedMonthNames = null;
+ leapYearMonthNames = null;
+ formatFlags = DateTimeFormatFlags.NotInitialized;
+
+ allShortDatePatterns = null;
+ allLongDatePatterns = null;
+ allYearMonthPatterns = null;
+ dateTimeOffsetPattern = null;
+
+ // The defaults need reset as well:
+ longDatePattern = null;
+ shortDatePattern = null;
+ yearMonthPattern = null;
+
+ // These properies are not in the OS data, but they are dependent on the values like shortDatePattern.
+ fullDateTimePattern = null; // Long date + long time
+ generalShortTimePattern = null; // short date + short time
+ generalLongTimePattern = null; // short date + long time
+
+ // Derived item that changes
+ dateSeparator = null;
+
+ // We don't need to do these because they are not changed by changing calendar
+ // amDesignator
+ // pmDesignator
+ // timeSeparator
+ // longTimePattern
+ // firstDayOfWeek
+ // calendarWeekRule
+
+ // remember to reload tokens
+ ClearTokenHashTable();
+ }
+
+ // Remember the new calendar
+ calendar = value;
+ InitializeOverridableProperties(_cultureData, calendar.ID);
+
+ // We succeeded, return
+ return;
+ }
+ }
+
+ // The assigned calendar is not a valid calendar for this culture, throw
+ throw new ArgumentOutOfRangeException("value", SR.Argument_InvalidCalendar);
+ }
+ }
+
+ private CalendarId[] OptionalCalendars
+ {
+ get
+ {
+ if (this.optionalCalendars == null)
+ {
+ this.optionalCalendars = _cultureData.CalendarIds;
+ }
+ return (this.optionalCalendars);
+ }
+ }
+
+ /*=================================GetEra==========================
+ **Action: Get the era value by parsing the name of the era.
+ **Returns: The era value for the specified era name.
+ ** -1 if the name of the era is not valid or not supported.
+ **Arguments: eraName the name of the era.
+ **Exceptions: None.
+ ============================================================================*/
+
+
+ public int GetEra(String eraName)
+ {
+ if (eraName == null)
+ {
+ throw new ArgumentNullException("eraName",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // The Era Name and Abbreviated Era Name
+ // for Taiwan Calendar on non-Taiwan SKU returns empty string (which
+ // would be matched below) but we don't want the empty string to give
+ // us an Era number
+ // confer 85900 DTFI.GetEra("") should fail on all cultures
+ if (eraName.Length == 0)
+ {
+ return (-1);
+ }
+
+ // The following is based on the assumption that the era value is starting from 1, and has a
+ // serial values.
+ // If that ever changes, the code has to be changed.
+
+ // The calls to String.Compare should use the current culture for the string comparisons, but the
+ // invariant culture when comparing against the english names.
+ for (int i = 0; i < EraNames.Length; i++)
+ {
+ // Compare the era name in a case-insensitive way for the appropriate culture.
+ if (m_eraNames[i].Length > 0)
+ {
+ if (this.Culture.CompareInfo.Compare(eraName, m_eraNames[i], CompareOptions.IgnoreCase) == 0)
+ {
+ return (i + 1);
+ }
+ }
+ }
+ for (int i = 0; i < AbbreviatedEraNames.Length; i++)
+ {
+ // Compare the abbreviated era name in a case-insensitive way for the appropriate culture.
+ if (this.Culture.CompareInfo.Compare(eraName, m_abbrevEraNames[i], CompareOptions.IgnoreCase) == 0)
+ {
+ return (i + 1);
+ }
+ }
+ for (int i = 0; i < AbbreviatedEnglishEraNames.Length; i++)
+ {
+ // this comparison should use the InvariantCulture. The English name could have linguistically
+ // interesting characters.
+ if (CultureInfo.InvariantCulture.CompareInfo.Compare(eraName, m_abbrevEnglishEraNames[i], CompareOptions.IgnoreCase) == 0)
+ {
+ return (i + 1);
+ }
+ }
+ return (-1);
+ }
+
+
+ internal String[] EraNames
+ {
+ get
+ {
+ if (this.m_eraNames == null)
+ {
+ this.m_eraNames = _cultureData.EraNames(Calendar.ID); ;
+ }
+ return (this.m_eraNames);
+ }
+ }
+
+ /*=================================GetEraName==========================
+ **Action: Get the name of the era for the specified era value.
+ **Returns: The name of the specified era.
+ **Arguments:
+ ** era the era value.
+ **Exceptions:
+ ** ArguementException if the era valie is invalid.
+ ============================================================================*/
+
+ // Era names are 1 indexed
+ public String GetEraName(int era)
+ {
+ if (era == Calendar.CurrentEra)
+ {
+ era = Calendar.CurrentEraValue;
+ }
+
+ // The following is based on the assumption that the era value is starting from 1, and has a
+ // serial values.
+ // If that ever changes, the code has to be changed.
+ if ((--era) < EraNames.Length && (era >= 0))
+ {
+ return (m_eraNames[era]);
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal String[] AbbreviatedEraNames
+ {
+ get
+ {
+ if (this.m_abbrevEraNames == null)
+ {
+ this.m_abbrevEraNames = _cultureData.AbbrevEraNames(Calendar.ID);
+ }
+ return (this.m_abbrevEraNames);
+ }
+ }
+
+ // Era names are 1 indexed
+ public String GetAbbreviatedEraName(int era)
+ {
+ if (AbbreviatedEraNames.Length == 0)
+ {
+ // If abbreviation era name is not used in this culture,
+ // return the full era name.
+ return (GetEraName(era));
+ }
+ if (era == Calendar.CurrentEra)
+ {
+ era = Calendar.CurrentEraValue;
+ }
+ if ((--era) < m_abbrevEraNames.Length && (era >= 0))
+ {
+ return (m_abbrevEraNames[era]);
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal String[] AbbreviatedEnglishEraNames
+ {
+ get
+ {
+ if (this.m_abbrevEnglishEraNames == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.AbbreviatedEnglishEraNames] Expected Calendar.ID > 0");
+ this.m_abbrevEnglishEraNames = _cultureData.AbbreviatedEnglishEraNames(Calendar.ID);
+ }
+ return (this.m_abbrevEnglishEraNames);
+ }
+ }
+
+
+ // Note that cultureData derives this from the short date format (unless someone's set this previously)
+ // Note that this property is quite undesirable.
+ internal String DateSeparator
+ {
+ get
+ {
+ if (this.dateSeparator == null)
+ {
+ this.dateSeparator = _cultureData.DateSeparator(Calendar.ID);
+ }
+ Contract.Assert(this.dateSeparator != null, "DateTimeFormatInfo.DateSeparator, dateSeparator != null");
+ return (this.dateSeparator);
+ }
+ set
+ {
+ throw null;
+ }
+ }
+
+
+ public DayOfWeek FirstDayOfWeek
+ {
+ get
+ {
+ if (this.firstDayOfWeek == -1)
+ {
+ this.firstDayOfWeek = _cultureData.IFIRSTDAYOFWEEK;
+ }
+ Contract.Assert(this.firstDayOfWeek != -1, "DateTimeFormatInfo.FirstDayOfWeek, firstDayOfWeek != -1");
+
+ return ((DayOfWeek)this.firstDayOfWeek);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value >= DayOfWeek.Sunday && value <= DayOfWeek.Saturday)
+ {
+ firstDayOfWeek = (int)value;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(
+ "value", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ }
+ }
+
+ public CalendarWeekRule CalendarWeekRule
+ {
+ get
+ {
+ if (this.calendarWeekRule == -1)
+ {
+ this.calendarWeekRule = _cultureData.IFIRSTWEEKOFYEAR;
+ }
+ Contract.Assert(this.calendarWeekRule != -1, "DateTimeFormatInfo.CalendarWeekRule, calendarWeekRule != -1");
+ return ((CalendarWeekRule)this.calendarWeekRule);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value >= CalendarWeekRule.FirstDay && value <= CalendarWeekRule.FirstFourDayWeek)
+ {
+ calendarWeekRule = (int)value;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(
+ "value", SR.Format(SR.ArgumentOutOfRange_Range,
+ CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));
+ }
+ }
+ }
+
+ public String FullDateTimePattern
+ {
+ get
+ {
+ if (fullDateTimePattern == null)
+ {
+ fullDateTimePattern = LongDatePattern + " " + LongTimePattern;
+ }
+ return (fullDateTimePattern);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ fullDateTimePattern = value;
+ }
+ }
+
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String LongDatePattern
+ {
+ get
+ {
+ // Initialize our long date pattern from the 1st array value if not set
+ if (this.longDatePattern == null)
+ {
+ // Initialize our data
+ this.longDatePattern = this.UnclonedLongDatePatterns[0];
+ }
+
+ return this.longDatePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.longDatePattern = value;
+
+ // Clear the token hash table
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ this.fullDateTimePattern = null;
+ }
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String LongTimePattern
+ {
+ get
+ {
+ // Initialize our long time pattern from the 1st array value if not set
+ if (this.longTimePattern == null)
+ {
+ // Initialize our data
+ this.longTimePattern = this.UnclonedLongTimePatterns[0];
+ }
+
+ return this.longTimePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.longTimePattern = value;
+
+ // Clear the token hash table
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ this.fullDateTimePattern = null; // Full date = long date + long Time
+ this.generalLongTimePattern = null; // General long date = short date + long Time
+ this.dateTimeOffsetPattern = null;
+ }
+ }
+
+
+ // Note: just to be confusing there's only 1 month day pattern, not a whole list
+ public String MonthDayPattern
+ {
+ get
+ {
+ if (this.monthDayPattern == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.MonthDayPattern] Expected calID > 0");
+ this.monthDayPattern = _cultureData.MonthDay(Calendar.ID);
+ }
+ Contract.Assert(this.monthDayPattern != null, "DateTimeFormatInfo.MonthDayPattern, monthDayPattern != null");
+ return (this.monthDayPattern);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ this.monthDayPattern = value;
+ }
+ }
+
+
+ public String PMDesignator
+ {
+ // auto-generated
+ get
+ {
+ if (this.pmDesignator == null)
+ {
+ this.pmDesignator = _cultureData.SPM2359;
+ }
+ Contract.Assert(this.pmDesignator != null, "DateTimeFormatInfo.PMDesignator, pmDesignator != null");
+ return (this.pmDesignator);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ ClearTokenHashTable();
+
+ pmDesignator = value;
+ }
+ }
+
+
+ public String RFC1123Pattern
+ {
+ get
+ {
+ return (rfc1123Pattern);
+ }
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String ShortDatePattern
+ {
+ get
+ {
+ // Initialize our short date pattern from the 1st array value if not set
+ if (this.shortDatePattern == null)
+ {
+ // Initialize our data
+ this.shortDatePattern = this.UnclonedShortDatePatterns[0];
+ }
+
+ return this.shortDatePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.shortDatePattern = value;
+
+ // Clear the token hash table, note that even short dates could require this
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ generalLongTimePattern = null; // General long time = short date + long time
+ generalShortTimePattern = null; // General short time = short date + short Time
+ dateTimeOffsetPattern = null;
+ }
+ }
+
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String ShortTimePattern
+ {
+ get
+ {
+ // Initialize our short time pattern from the 1st array value if not set
+ if (this.shortTimePattern == null)
+ {
+ // Initialize our data
+ this.shortTimePattern = this.UnclonedShortTimePatterns[0];
+ }
+ return this.shortTimePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.shortTimePattern = value;
+
+ // Clear the token hash table, note that even short times could require this
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ generalShortTimePattern = null; // General short date = short date + short time.
+ }
+ }
+
+
+ public String SortableDateTimePattern
+ {
+ get
+ {
+ return (sortableDateTimePattern);
+ }
+ }
+
+ /*=================================GeneralShortTimePattern=====================
+ **Property: Return the pattern for 'g' general format: shortDate + short time
+ **Note: This is used by DateTimeFormat.cs to get the pattern for 'g'
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody asks for the general format.
+ ==============================================================================*/
+
+ internal String GeneralShortTimePattern
+ {
+ get
+ {
+ if (generalShortTimePattern == null)
+ {
+ generalShortTimePattern = ShortDatePattern + " " + ShortTimePattern;
+ }
+ return (generalShortTimePattern);
+ }
+ }
+
+ /*=================================GeneralLongTimePattern=====================
+ **Property: Return the pattern for 'g' general format: shortDate + Long time
+ **Note: This is used by DateTimeFormat.cs to get the pattern for 'g'
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody asks for the general format.
+ ==============================================================================*/
+
+ internal String GeneralLongTimePattern
+ {
+ get
+ {
+ if (generalLongTimePattern == null)
+ {
+ generalLongTimePattern = ShortDatePattern + " " + LongTimePattern;
+ }
+ return (generalLongTimePattern);
+ }
+ }
+
+ /*=================================DateTimeOffsetPattern==========================
+ **Property: Return the default pattern DateTimeOffset : shortDate + long time + time zone offset
+ **Note: This is used by DateTimeFormat.cs to get the pattern for short Date + long time + time zone offset
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody uses this form
+ ==============================================================================*/
+
+ /*=================================DateTimeOffsetPattern==========================
+ **Property: Return the default pattern DateTimeOffset : shortDate + long time + time zone offset
+ **Note: This is used by DateTimeFormat.cs to get the pattern for short Date + long time + time zone offset
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody uses this form
+ ==============================================================================*/
+
+ internal String DateTimeOffsetPattern
+ {
+ get
+ {
+ if (dateTimeOffsetPattern == null)
+ {
+ string dateTimePattern = ShortDatePattern + " " + LongTimePattern;
+
+ /* LongTimePattern might contain a "z" as part of the format string in which case we don't want to append a time zone offset */
+
+ bool foundZ = false;
+ bool inQuote = false;
+ char quote = '\'';
+ for (int i = 0; !foundZ && i < LongTimePattern.Length; i++)
+ {
+ switch (LongTimePattern[i])
+ {
+ case 'z':
+ /* if we aren't in a quote, we've found a z */
+ foundZ = !inQuote;
+ /* we'll fall out of the loop now because the test includes !foundZ */
+ break;
+ case '\'':
+ case '\"':
+ if (inQuote && (quote == LongTimePattern[i]))
+ {
+ /* we were in a quote and found a matching exit quote, so we are outside a quote now */
+ inQuote = false;
+ }
+ else if (!inQuote)
+ {
+ quote = LongTimePattern[i];
+ inQuote = true;
+ }
+ else
+ {
+ /* we were in a quote and saw the other type of quote character, so we are still in a quote */
+ }
+ break;
+ case '%':
+ case '\\':
+ i++; /* skip next character that is escaped by this backslash */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!foundZ)
+ {
+ dateTimePattern = dateTimePattern + " zzz";
+ }
+
+ dateTimeOffsetPattern = dateTimePattern;
+ }
+ return (dateTimeOffsetPattern);
+ }
+ }
+
+ // Note that cultureData derives this from the long time format (unless someone's set this previously)
+ // Note that this property is quite undesirable.
+ internal String TimeSeparator
+ {
+ get
+ {
+ if (timeSeparator == null)
+ {
+ timeSeparator = _cultureData.TimeSeparator;
+ }
+ Contract.Assert(this.timeSeparator != null, "DateTimeFormatInfo.TimeSeparator, timeSeparator != null");
+ return (timeSeparator);
+ }
+
+ set
+ {
+ throw null;
+ }
+ }
+
+
+ public String UniversalSortableDateTimePattern
+ {
+ get
+ {
+ return (universalSortableDateTimePattern);
+ }
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String YearMonthPattern
+ {
+ get
+ {
+ // Initialize our year/month pattern from the 1st array value if not set
+ if (this.yearMonthPattern == null)
+ {
+ // Initialize our data
+ this.yearMonthPattern = this.UnclonedYearMonthPatterns[0];
+ }
+ return this.yearMonthPattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.yearMonthPattern = value;
+
+ // Clear the token hash table, note that even short times could require this
+ ClearTokenHashTable();
+ }
+ }
+
+ //
+ // Check if a string array contains a null value, and throw ArgumentNullException with parameter name "value"
+ //
+ private static void CheckNullValue(String[] values, int length)
+ {
+ Contract.Requires(values != null, "value != null");
+ Contract.Requires(values.Length >= length);
+ for (int i = 0; i < length; i++)
+ {
+ if (values[i] == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_ArrayValue);
+ }
+ }
+ }
+
+
+ public String[] AbbreviatedDayNames
+ {
+ get
+ {
+ return ((String[])internalGetAbbreviatedDayOfWeekNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 7)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length);
+ ClearTokenHashTable();
+
+ abbreviatedDayNames = value;
+ }
+ }
+
+ // Returns the string array of the one-letter day of week names.
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String[] ShortestDayNames
+ {
+ get
+ {
+ return ((String[])internalGetSuperShortDayNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 7)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length);
+ this.m_superShortDayNames = value;
+ }
+ }
+
+
+ public String[] DayNames
+ {
+ get
+ {
+ return ((String[])internalGetDayOfWeekNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 7)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length);
+ ClearTokenHashTable();
+
+ dayNames = value;
+ }
+ }
+
+
+ public String[] AbbreviatedMonthNames
+ {
+ get
+ {
+ return ((String[])internalGetAbbreviatedMonthNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ ClearTokenHashTable();
+ abbreviatedMonthNames = value;
+ }
+ }
+
+
+ public String[] MonthNames
+ {
+ get
+ {
+ return ((String[])internalGetMonthNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ monthNames = value;
+ ClearTokenHashTable();
+ }
+ }
+
+ // Whitespaces that we allow in the month names.
+ // U+00a0 is non-breaking space.
+ private static readonly char[] s_monthSpaces = { ' ', '\u00a0' };
+
+ internal bool HasSpacesInMonthNames
+ {
+ get
+ {
+ return (FormatFlags & DateTimeFormatFlags.UseSpacesInMonthNames) != 0;
+ }
+ }
+
+ internal bool HasSpacesInDayNames
+ {
+ get
+ {
+ return (FormatFlags & DateTimeFormatFlags.UseSpacesInDayNames) != 0;
+ }
+ }
+
+
+ //
+ // internalGetMonthName
+ //
+ // Actions: Return the month name using the specified MonthNameStyles in either abbreviated form
+ // or full form.
+ // Arguments:
+ // month
+ // style To indicate a form like regular/genitive/month name in a leap year.
+ // abbreviated When true, return abbreviated form. Otherwise, return a full form.
+ // Exceptions:
+ // ArgumentOutOfRangeException When month name is invalid.
+ //
+ internal String internalGetMonthName(int month, MonthNameStyles style, bool abbreviated)
+ {
+ //
+ // Right now, style is mutual exclusive, but I make the style to be flag so that
+ // maybe we can combine flag if there is such a need.
+ //
+ String[] monthNamesArray = null;
+ switch (style)
+ {
+ case MonthNameStyles.Genitive:
+ monthNamesArray = internalGetGenitiveMonthNames(abbreviated);
+ break;
+ case MonthNameStyles.LeapYear:
+ monthNamesArray = internalGetLeapYearMonthNames(/*abbreviated*/);
+ break;
+ default:
+ monthNamesArray = (abbreviated ? internalGetAbbreviatedMonthNames() : internalGetMonthNames());
+ break;
+ }
+ // The month range is from 1 ~ this.m_monthNames.Length
+ // (actually is 13 right now for all cases)
+ if ((month < 1) || (month > monthNamesArray.Length))
+ {
+ throw new ArgumentOutOfRangeException(
+ "month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, monthNamesArray.Length));
+ }
+ return (monthNamesArray[month - 1]);
+ }
+
+ //
+ // internalGetGenitiveMonthNames
+ //
+ // Action: Retrieve the array which contains the month names in genitive form.
+ // If this culture does not use the gentive form, the normal month name is returned.
+ // Arguments:
+ // abbreviated When true, return abbreviated form. Otherwise, return a full form.
+ //
+ private String[] internalGetGenitiveMonthNames(bool abbreviated)
+ {
+ if (abbreviated)
+ {
+ if (this.m_genitiveAbbreviatedMonthNames == null)
+ {
+ this.m_genitiveAbbreviatedMonthNames = _cultureData.AbbreviatedGenitiveMonthNames(this.Calendar.ID);
+ Contract.Assert(this.m_genitiveAbbreviatedMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 abbreviated genitive month names in a year");
+ }
+ return (this.m_genitiveAbbreviatedMonthNames);
+ }
+
+ if (this.genitiveMonthNames == null)
+ {
+ this.genitiveMonthNames = _cultureData.GenitiveMonthNames(this.Calendar.ID);
+ Contract.Assert(this.genitiveMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 genitive month names in a year");
+ }
+ return (this.genitiveMonthNames);
+ }
+
+ //
+ // internalGetLeapYearMonthNames
+ //
+ // Actions: Retrieve the month names used in a leap year.
+ // If this culture does not have different month names in a leap year, the normal month name is returned.
+ // Agruments: None. (can use abbreviated later if needed)
+ //
+ internal String[] internalGetLeapYearMonthNames(/*bool abbreviated*/)
+ {
+ if (this.leapYearMonthNames == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.internalGetLeapYearMonthNames] Expected Calendar.ID > 0");
+ this.leapYearMonthNames = _cultureData.LeapYearMonthNames(Calendar.ID);
+ Contract.Assert(this.leapYearMonthNames.Length == 13,
+ "[DateTimeFormatInfo.internalGetLeapYearMonthNames] Expepcted 13 leap year month names");
+ }
+ return (leapYearMonthNames);
+ }
+
+
+ public String GetAbbreviatedDayName(DayOfWeek dayofweek)
+ {
+ if ((int)dayofweek < 0 || (int)dayofweek > 6)
+ {
+ throw new ArgumentOutOfRangeException(
+ "dayofweek", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ Contract.EndContractBlock();
+ //
+ // Don't call the public property AbbreviatedDayNames here since a clone is needed in that
+ // property, so it will be slower. Instead, use GetAbbreviatedDayOfWeekNames() directly.
+ //
+ return (internalGetAbbreviatedDayOfWeekNames()[(int)dayofweek]);
+ }
+
+ // Get all possible combination of inputs
+ private static String[] GetCombinedPatterns(String[] patterns1, String[] patterns2, String connectString)
+ {
+ Contract.Requires(patterns1 != null);
+ Contract.Requires(patterns2 != null);
+
+ // Get array size
+ String[] result = new String[patterns1.Length * patterns2.Length];
+
+ // Counter of actual results
+ int k = 0;
+ for (int i = 0; i < patterns1.Length; i++)
+ {
+ for (int j = 0; j < patterns2.Length; j++)
+ {
+ // Can't combine if null or empty
+ result[k++] = patterns1[i] + connectString + patterns2[j];
+ }
+ }
+
+ // Return the combinations
+ return (result);
+ }
+
+
+ // auto-generated
+ internal String[] GetAllDateTimePatterns(char format)
+ {
+ Contract.Ensures(Contract.Result<String[]>() != null);
+ String[] result = null;
+
+ switch (format)
+ {
+ case 'd':
+ result = this.AllShortDatePatterns;
+ break;
+ case 'D':
+ result = this.AllLongDatePatterns;
+ break;
+ case 'f':
+ result = GetCombinedPatterns(AllLongDatePatterns, AllShortTimePatterns, " ");
+ break;
+ case 'F':
+ case 'U':
+ result = GetCombinedPatterns(AllLongDatePatterns, AllLongTimePatterns, " ");
+ break;
+ case 'g':
+ result = GetCombinedPatterns(AllShortDatePatterns, AllShortTimePatterns, " ");
+ break;
+ case 'G':
+ result = GetCombinedPatterns(AllShortDatePatterns, AllLongTimePatterns, " ");
+ break;
+ case 'm':
+ case 'M':
+ result = new String[] { MonthDayPattern };
+ break;
+ case 'o':
+ case 'O':
+ result = new String[] { RoundtripFormat };
+ break;
+ case 'r':
+ case 'R':
+ result = new String[] { rfc1123Pattern };
+ break;
+ case 's':
+ result = new String[] { sortableDateTimePattern };
+ break;
+ case 't':
+ result = this.AllShortTimePatterns;
+ break;
+ case 'T':
+ result = this.AllLongTimePatterns;
+ break;
+ case 'u':
+ result = new String[] { UniversalSortableDateTimePattern };
+ break;
+ case 'y':
+ case 'Y':
+ result = this.AllYearMonthPatterns;
+ break;
+ default:
+ throw new ArgumentException(SR.Format_BadFormatSpecifier, "format");
+ }
+ return (result);
+ }
+
+
+ public String GetDayName(DayOfWeek dayofweek)
+ {
+ if ((int)dayofweek < 0 || (int)dayofweek > 6)
+ {
+ throw new ArgumentOutOfRangeException(
+ "dayofweek", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ Contract.EndContractBlock();
+
+ // Use the internal one so that we don't clone the array unnecessarily
+ return (internalGetDayOfWeekNames()[(int)dayofweek]);
+ }
+
+
+
+ public String GetAbbreviatedMonthName(int month)
+ {
+ if (month < 1 || month > 13)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, 13));
+ }
+ Contract.EndContractBlock();
+ // Use the internal one so we don't clone the array unnecessarily
+ return (internalGetAbbreviatedMonthNames()[month - 1]);
+ }
+
+
+ public String GetMonthName(int month)
+ {
+ if (month < 1 || month > 13)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, 13));
+ }
+ Contract.EndContractBlock();
+ // Use the internal one so we don't clone the array unnecessarily
+ return (internalGetMonthNames()[month - 1]);
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ //
+ // The resulting [] can get returned to the calling app, so clone it.
+ private static string[] GetMergedPatterns(string[] patterns, string defaultPattern)
+ {
+ Contract.Assert(patterns != null && patterns.Length > 0,
+ "[DateTimeFormatInfo.GetMergedPatterns]Expected array of at least one pattern");
+ Contract.Assert(defaultPattern != null,
+ "[DateTimeFormatInfo.GetMergedPatterns]Expected non null default string");
+
+ // If the default happens to be the first in the list just return (a cloned) copy
+ if (defaultPattern == patterns[0])
+ {
+ return (string[])patterns.Clone();
+ }
+
+ // We either need a bigger list, or the pattern from the list.
+ int i;
+ for (i = 0; i < patterns.Length; i++)
+ {
+ // Stop if we found it
+ if (defaultPattern == patterns[i])
+ break;
+ }
+
+ // Either way we're going to need a new array
+ string[] newPatterns;
+
+ // Did we find it
+ if (i < patterns.Length)
+ {
+ // Found it, output will be same size
+ newPatterns = (string[])patterns.Clone();
+
+ // Have to move [0] item to [i] so we can re-write default at [0]
+ // (remember defaultPattern == [i] so this is OK)
+ newPatterns[i] = newPatterns[0];
+ }
+ else
+ {
+ // Not found, make room for it
+ newPatterns = new String[patterns.Length + 1];
+
+ // Copy existing array
+ Array.Copy(patterns, 0, newPatterns, 1, patterns.Length);
+ }
+
+ // Remember the default
+ newPatterns[0] = defaultPattern;
+
+ // Return the reconstructed list
+ return newPatterns;
+ }
+
+ // Needed by DateTimeFormatInfo and DateTimeFormat
+ internal const String RoundtripFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";
+ internal const String RoundtripDateTimeUnfixed = "yyyy'-'MM'-'ddTHH':'mm':'ss zzz";
+
+ // Default string isn't necessarily in our string array, so get the
+ // merged patterns of both
+ private String[] AllYearMonthPatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedYearMonthPatterns, this.YearMonthPattern);
+ }
+ }
+
+ private String[] AllShortDatePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedShortDatePatterns, this.ShortDatePattern);
+ }
+ }
+
+ private String[] AllShortTimePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedShortTimePatterns, this.ShortTimePattern);
+ }
+ }
+
+ private String[] AllLongDatePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedLongDatePatterns, this.LongDatePattern);
+ }
+ }
+
+ private String[] AllLongTimePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedLongTimePatterns, this.LongTimePattern);
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllYearMonthPatterns
+ private String[] UnclonedYearMonthPatterns
+ {
+ get
+ {
+ if (this.allYearMonthPatterns == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected Calendar.ID > 0");
+ this.allYearMonthPatterns = _cultureData.YearMonths(this.Calendar.ID);
+ Contract.Assert(this.allYearMonthPatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected some year month patterns");
+ }
+
+ return this.allYearMonthPatterns;
+ }
+ }
+
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllShortDatePatterns
+ private String[] UnclonedShortDatePatterns
+ {
+ get
+ {
+ if (allShortDatePatterns == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected Calendar.ID > 0");
+ this.allShortDatePatterns = _cultureData.ShortDates(this.Calendar.ID);
+ Contract.Assert(this.allShortDatePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected some short date patterns");
+ }
+
+ return this.allShortDatePatterns;
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllLongDatePatterns
+ private String[] UnclonedLongDatePatterns
+ {
+ get
+ {
+ if (allLongDatePatterns == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected Calendar.ID > 0");
+ this.allLongDatePatterns = _cultureData.LongDates(this.Calendar.ID);
+ Contract.Assert(this.allLongDatePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected some long date patterns");
+ }
+
+ return this.allLongDatePatterns;
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllShortTimePatterns
+ private String[] UnclonedShortTimePatterns
+ {
+ get
+ {
+ if (this.allShortTimePatterns == null)
+ {
+ this.allShortTimePatterns = _cultureData.ShortTimes;
+ Contract.Assert(this.allShortTimePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedShortTimePatterns] Expected some short time patterns");
+ }
+
+ return this.allShortTimePatterns;
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllLongTimePatterns
+ private String[] UnclonedLongTimePatterns
+ {
+ get
+ {
+ if (this.allLongTimePatterns == null)
+ {
+ this.allLongTimePatterns = _cultureData.LongTimes;
+ Contract.Assert(this.allLongTimePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedLongTimePatterns] Expected some long time patterns");
+ }
+
+ return this.allLongTimePatterns;
+ }
+ }
+
+ public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
+ {
+ if (dtfi == null)
+ {
+ throw new ArgumentNullException("dtfi",
+ SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ if (dtfi.IsReadOnly)
+ {
+ return (dtfi);
+ }
+ DateTimeFormatInfo newInfo = (DateTimeFormatInfo)(dtfi.MemberwiseClone());
+ // We can use the data member calendar in the setter, instead of the property Calendar,
+ // since the cloned copy should have the same state as the original copy.
+ newInfo.calendar = Calendar.ReadOnly(dtfi.Calendar);
+ newInfo._isReadOnly = true;
+ return (newInfo);
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return (_isReadOnly);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String[] AbbreviatedMonthGenitiveNames
+ {
+ get
+ {
+ return ((String[])internalGetGenitiveMonthNames(true).Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ ClearTokenHashTable();
+ this.m_genitiveAbbreviatedMonthNames = value;
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String[] MonthGenitiveNames
+ {
+ get
+ {
+ return ((String[])internalGetGenitiveMonthNames(false).Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ genitiveMonthNames = value;
+ ClearTokenHashTable();
+ }
+ }
+
+ //
+ // Positive TimeSpan Pattern
+ //
+
+ private string _fullTimeSpanPositivePattern;
+ internal String FullTimeSpanPositivePattern
+ {
+ get
+ {
+ if (_fullTimeSpanPositivePattern == null)
+ {
+ CultureData cultureDataWithoutUserOverrides;
+ if (_cultureData.UseUserOverride)
+ cultureDataWithoutUserOverrides = CultureData.GetCultureData(_cultureData.CultureName, false);
+ else
+ cultureDataWithoutUserOverrides = _cultureData;
+ String decimalSeparator = new NumberFormatInfo(cultureDataWithoutUserOverrides).NumberDecimalSeparator;
+
+ _fullTimeSpanPositivePattern = "d':'h':'mm':'ss'" + decimalSeparator + "'FFFFFFF";
+ }
+ return _fullTimeSpanPositivePattern;
+ }
+ }
+
+ //
+ // Negative TimeSpan Pattern
+ //
+
+ private string _fullTimeSpanNegativePattern;
+ internal String FullTimeSpanNegativePattern
+ {
+ get
+ {
+ if (_fullTimeSpanNegativePattern == null)
+ _fullTimeSpanNegativePattern = "'-'" + FullTimeSpanPositivePattern;
+ return _fullTimeSpanNegativePattern;
+ }
+ }
+
+ //
+ // Get suitable CompareInfo from current DTFI object.
+ //
+ internal CompareInfo CompareInfo
+ {
+ get
+ {
+ if (_compareInfo == null)
+ {
+ // We use the regular GetCompareInfo here to make sure the created CompareInfo object is stored in the
+ // CompareInfo cache. otherwise we would just create CompareInfo using _cultureData.
+ _compareInfo = CompareInfo.GetCompareInfo(_cultureData.SCOMPAREINFO);
+ }
+
+ return _compareInfo;
+ }
+ }
+
+
+ internal const DateTimeStyles InvalidDateTimeStyles = ~(DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite
+ | DateTimeStyles.AllowInnerWhite | DateTimeStyles.NoCurrentDateDefault
+ | DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeLocal
+ | DateTimeStyles.AssumeUniversal | DateTimeStyles.RoundtripKind);
+
+ internal static void ValidateStyles(DateTimeStyles style, String parameterName)
+ {
+ if ((style & InvalidDateTimeStyles) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidDateTimeStyles, parameterName);
+ }
+ if (((style & (DateTimeStyles.AssumeLocal)) != 0) && ((style & (DateTimeStyles.AssumeUniversal)) != 0))
+ {
+ throw new ArgumentException(SR.Argument_ConflictingDateTimeStyles, parameterName);
+ }
+ Contract.EndContractBlock();
+ if (((style & DateTimeStyles.RoundtripKind) != 0)
+ && ((style & (DateTimeStyles.AssumeLocal | DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)) != 0))
+ {
+ throw new ArgumentException(SR.Argument_ConflictingDateTimeRoundtripStyles, parameterName);
+ }
+ }
+
+ //
+ // Actions: Return the internal flag used in formatting and parsing.
+ // The flag can be used to indicate things like if genitive forms is used in this DTFi, or if leap year gets different month names.
+ //
+ internal DateTimeFormatFlags FormatFlags
+ {
+ get
+ {
+ if (formatFlags == DateTimeFormatFlags.NotInitialized)
+ {
+ // Build the format flags from the data in this DTFI
+ formatFlags = DateTimeFormatFlags.None;
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth(
+ MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames(
+ MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames);
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID);
+ }
+ return (formatFlags);
+ }
+ }
+
+ internal Boolean HasForceTwoDigitYears
+ {
+ get
+ {
+ switch (calendar.ID)
+ {
+ // Handle Japanese and Taiwan cases.
+ // If is y/yy, do not get (year % 100). "y" will print
+ // year without leading zero. "yy" will print year with two-digit in leading zero.
+ // If pattern is yyy/yyyy/..., print year value with two-digit in leading zero.
+ // So year 5 is "05", and year 125 is "125".
+ // The reason for not doing (year % 100) is for Taiwan calendar.
+ // If year 125, then output 125 and not 25.
+ // Note: OS uses "yyyy" for Taiwan calendar by default.
+ case (CalendarId.JAPAN):
+ case (CalendarId.TAIWAN):
+ return true;
+ }
+ return false;
+ }
+ }
+
+ // Returns whether the YearMonthAdjustment function has any fix-up work to do for this culture/calendar.
+ internal Boolean HasYearMonthAdjustment
+ {
+ get
+ {
+ return ((FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0);
+ }
+ }
+
+ // This is a callback that the parser can make back into the DTFI to let it fiddle with special
+ // cases associated with that culture or calendar. Currently this only has special cases for
+ // the Hebrew calendar, but this could be extended to other cultures.
+ //
+ // The return value is whether the year and month are actually valid for this calendar.
+ internal Boolean YearMonthAdjustment(ref int year, ref int month, Boolean parsedMonthName)
+ {
+ if ((FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0)
+ {
+ // Special rules to fix up the Hebrew year/month
+
+ // When formatting, we only format up to the hundred digit of the Hebrew year, although Hebrew year is now over 5000.
+ // E.g. if the year is 5763, we only format as 763.
+ if (year < 1000)
+ {
+ year += 5000;
+ }
+
+ // Because we need to calculate leap year, we should fall out now for an invalid year.
+ if (year < Calendar.GetYear(Calendar.MinSupportedDateTime) || year > Calendar.GetYear(Calendar.MaxSupportedDateTime))
+ {
+ return false;
+ }
+
+ // To handle leap months, the set of month names in the symbol table does not always correspond to the numbers.
+ // For non-leap years, month 7 (Adar Bet) is not present, so we need to make using this month invalid and
+ // shuffle the other months down.
+ if (parsedMonthName)
+ {
+ if (!Calendar.IsLeapYear(year))
+ {
+ if (month >= 8)
+ {
+ month--;
+ }
+ else if (month == 7)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ //
+ // DateTimeFormatInfo tokenizer. This is used by DateTime.Parse() to break input string into tokens.
+ //
+
+ private TokenHashValue[] _dtfiTokenHash;
+
+ private const int TOKEN_HASH_SIZE = 199;
+ private const int SECOND_PRIME = 197;
+ private const String dateSeparatorOrTimeZoneOffset = "-";
+ private const String invariantDateSeparator = "/";
+ private const String invariantTimeSeparator = ":";
+
+ //
+ // Common Ignorable Symbols
+ //
+ internal const String IgnorablePeriod = ".";
+ internal const String IgnorableComma = ",";
+
+ //
+ // Year/Month/Day suffixes
+ //
+ internal const String CJKYearSuff = "\u5e74";
+ internal const String CJKMonthSuff = "\u6708";
+ internal const String CJKDaySuff = "\u65e5";
+
+ internal const String KoreanYearSuff = "\ub144";
+ internal const String KoreanMonthSuff = "\uc6d4";
+ internal const String KoreanDaySuff = "\uc77c";
+
+ internal const String KoreanHourSuff = "\uc2dc";
+ internal const String KoreanMinuteSuff = "\ubd84";
+ internal const String KoreanSecondSuff = "\ucd08";
+
+ internal const String CJKHourSuff = "\u6642";
+ internal const String ChineseHourSuff = "\u65f6";
+
+ internal const String CJKMinuteSuff = "\u5206";
+ internal const String CJKSecondSuff = "\u79d2";
+
+ internal const String LocalTimeMark = "T";
+
+ internal const String GMTName = "GMT";
+ internal const String ZuluName = "Z";
+
+ internal const String KoreanLangName = "ko";
+ internal const String JapaneseLangName = "ja";
+ internal const String EnglishLangName = "en";
+
+ private static volatile DateTimeFormatInfo s_jajpDTFI;
+ private static volatile DateTimeFormatInfo s_zhtwDTFI;
+
+ //
+ // Create a Japanese DTFI which uses JapaneseCalendar. This is used to parse
+ // date string with Japanese era name correctly even when the supplied DTFI
+ // does not use Japanese calendar.
+ // The created instance is stored in global s_jajpDTFI.
+ //
+ internal static DateTimeFormatInfo GetJapaneseCalendarDTFI()
+ {
+ DateTimeFormatInfo temp = s_jajpDTFI;
+ if (temp == null)
+ {
+ temp = new CultureInfo("ja-JP", false).DateTimeFormat;
+ temp.Calendar = JapaneseCalendar.GetDefaultInstance();
+ s_jajpDTFI = temp;
+ }
+ return (temp);
+ }
+
+ // Create a Taiwan DTFI which uses TaiwanCalendar. This is used to parse
+ // date string with era name correctly even when the supplied DTFI
+ // does not use Taiwan calendar.
+ // The created instance is stored in global s_zhtwDTFI.
+ internal static DateTimeFormatInfo GetTaiwanCalendarDTFI()
+ {
+ DateTimeFormatInfo temp = s_zhtwDTFI;
+ if (temp == null)
+ {
+ temp = new CultureInfo("zh-TW", false).DateTimeFormat;
+ temp.Calendar = TaiwanCalendar.GetDefaultInstance();
+ s_zhtwDTFI = temp;
+ }
+ return (temp);
+ }
+
+
+ // DTFI properties should call this when the setter are called.
+ private void ClearTokenHashTable()
+ {
+ _dtfiTokenHash = null;
+ formatFlags = DateTimeFormatFlags.NotInitialized;
+ }
+
+ internal TokenHashValue[] CreateTokenHashTable()
+ {
+ TokenHashValue[] temp = _dtfiTokenHash;
+ if (temp == null)
+ {
+ temp = new TokenHashValue[TOKEN_HASH_SIZE];
+
+ bool koreanLanguage = LanguageName.Equals(KoreanLangName);
+
+ string sep = this.TimeSeparator.Trim();
+ if (IgnorableComma != sep) InsertHash(temp, IgnorableComma, TokenType.IgnorableSymbol, 0);
+ if (IgnorablePeriod != sep) InsertHash(temp, IgnorablePeriod, TokenType.IgnorableSymbol, 0);
+
+ if (KoreanHourSuff != sep && CJKHourSuff != sep && ChineseHourSuff != sep)
+ {
+ //
+ // On the Macintosh, the default TimeSeparator is identical to the KoreanHourSuff, CJKHourSuff, or ChineseHourSuff for some cultures like
+ // ja-JP and ko-KR. In these cases having the same symbol inserted into the hash table with multiple TokenTypes causes undesirable
+ // DateTime.Parse behavior. For instance, the DateTimeFormatInfo.Tokenize() method might return SEP_DateOrOffset for KoreanHourSuff
+ // instead of SEP_HourSuff.
+ //
+ InsertHash(temp, this.TimeSeparator, TokenType.SEP_Time, 0);
+ }
+
+ InsertHash(temp, this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
+ InsertHash(temp, this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
+
+ // TODO: This ignores similar custom cultures
+ if (LanguageName.Equals("sq"))
+ {
+ // Albanian allows time formats like "12:00.PD"
+ InsertHash(temp, IgnorablePeriod + this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
+ InsertHash(temp, IgnorablePeriod + this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
+ }
+
+ // CJK suffix
+ InsertHash(temp, CJKYearSuff, TokenType.SEP_YearSuff, 0);
+ InsertHash(temp, KoreanYearSuff, TokenType.SEP_YearSuff, 0);
+ InsertHash(temp, CJKMonthSuff, TokenType.SEP_MonthSuff, 0);
+ InsertHash(temp, KoreanMonthSuff, TokenType.SEP_MonthSuff, 0);
+ InsertHash(temp, CJKDaySuff, TokenType.SEP_DaySuff, 0);
+ InsertHash(temp, KoreanDaySuff, TokenType.SEP_DaySuff, 0);
+
+ InsertHash(temp, CJKHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, ChineseHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, CJKMinuteSuff, TokenType.SEP_MinuteSuff, 0);
+ InsertHash(temp, CJKSecondSuff, TokenType.SEP_SecondSuff, 0);
+
+ // TODO: This ignores other custom cultures that might want to do something similar
+ if (koreanLanguage)
+ {
+ // Korean suffix
+ InsertHash(temp, KoreanHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, KoreanMinuteSuff, TokenType.SEP_MinuteSuff, 0);
+ InsertHash(temp, KoreanSecondSuff, TokenType.SEP_SecondSuff, 0);
+ }
+
+ if (LanguageName.Equals("ky"))
+ {
+ // For some cultures, the date separator works more like a comma, being allowed before or after any date part
+ InsertHash(temp, dateSeparatorOrTimeZoneOffset, TokenType.IgnorableSymbol, 0);
+ }
+ else
+ {
+ InsertHash(temp, dateSeparatorOrTimeZoneOffset, TokenType.SEP_DateOrOffset, 0);
+ }
+
+ String[] dateWords = null;
+ DateTimeFormatInfoScanner scanner = null;
+
+ // We need to rescan the date words since we're always synthetic
+ scanner = new DateTimeFormatInfoScanner();
+ m_dateWords = dateWords = scanner.GetDateWordsOfDTFI(this);
+ // Ensure the formatflags is initialized.
+ DateTimeFormatFlags flag = FormatFlags;
+
+ // For some cultures, the date separator works more like a comma, being allowed before or after any date part.
+ // In these cultures, we do not use normal date separator since we disallow date separator after a date terminal state.
+ // This is determined in DateTimeFormatInfoScanner. Use this flag to determine if we should treat date separator as ignorable symbol.
+ bool useDateSepAsIgnorableSymbol = false;
+
+ String monthPostfix = null;
+ if (dateWords != null)
+ {
+ // There are DateWords. It could be a real date word (such as "de"), or a monthPostfix.
+ // The monthPostfix starts with '\xfffe' (MonthPostfixChar), followed by the real monthPostfix.
+ for (int i = 0; i < dateWords.Length; i++)
+ {
+ switch (dateWords[i][0])
+ {
+ // This is a month postfix
+ case DateTimeFormatInfoScanner.MonthPostfixChar:
+ // Get the real month postfix.
+ monthPostfix = dateWords[i].Substring(1);
+ // Add the month name + postfix into the token.
+ AddMonthNames(temp, monthPostfix);
+ break;
+ case DateTimeFormatInfoScanner.IgnorableSymbolChar:
+ String symbol = dateWords[i].Substring(1);
+ InsertHash(temp, symbol, TokenType.IgnorableSymbol, 0);
+ if (this.DateSeparator.Trim(null).Equals(symbol))
+ {
+ // The date separator is the same as the ignorable symbol.
+ useDateSepAsIgnorableSymbol = true;
+ }
+ break;
+ default:
+ InsertHash(temp, dateWords[i], TokenType.DateWordToken, 0);
+ // TODO: This ignores similar custom cultures
+ if (LanguageName.Equals("eu"))
+ {
+ // Basque has date words with leading dots
+ InsertHash(temp, IgnorablePeriod + dateWords[i], TokenType.DateWordToken, 0);
+ }
+ break;
+ }
+ }
+ }
+
+ if (!useDateSepAsIgnorableSymbol)
+ {
+ // Use the normal date separator.
+ InsertHash(temp, this.DateSeparator, TokenType.SEP_Date, 0);
+ }
+ // Add the regular month names.
+ AddMonthNames(temp, null);
+
+ // Add the abbreviated month names.
+ for (int i = 1; i <= 13; i++)
+ {
+ InsertHash(temp, GetAbbreviatedMonthName(i), TokenType.MonthToken, i);
+ }
+
+
+ if ((FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0)
+ {
+ for (int i = 1; i <= 13; i++)
+ {
+ String str;
+ str = internalGetMonthName(i, MonthNameStyles.Genitive, false);
+ InsertHash(temp, str, TokenType.MonthToken, i);
+ }
+ }
+
+ if ((FormatFlags & DateTimeFormatFlags.UseLeapYearMonth) != 0)
+ {
+ for (int i = 1; i <= 13; i++)
+ {
+ String str;
+ str = internalGetMonthName(i, MonthNameStyles.LeapYear, false);
+ InsertHash(temp, str, TokenType.MonthToken, i);
+ }
+ }
+
+ for (int i = 0; i < 7; i++)
+ {
+ //String str = GetDayOfWeekNames()[i];
+ // We have to call public methods here to work with inherited DTFI.
+ String str = GetDayName((DayOfWeek)i);
+ InsertHash(temp, str, TokenType.DayOfWeekToken, i);
+
+ str = GetAbbreviatedDayName((DayOfWeek)i);
+ InsertHash(temp, str, TokenType.DayOfWeekToken, i);
+ }
+
+ int[] eras = calendar.Eras;
+ for (int i = 1; i <= eras.Length; i++)
+ {
+ InsertHash(temp, GetEraName(i), TokenType.EraToken, i);
+ InsertHash(temp, GetAbbreviatedEraName(i), TokenType.EraToken, i);
+ }
+
+ // TODO: This ignores other cultures that might want to do something similar
+ if (LanguageName.Equals(JapaneseLangName))
+ {
+ // Japanese allows day of week forms like: "(Tue)"
+ for (int i = 0; i < 7; i++)
+ {
+ String specialDayOfWeek = "(" + GetAbbreviatedDayName((DayOfWeek)i) + ")";
+ InsertHash(temp, specialDayOfWeek, TokenType.DayOfWeekToken, i);
+ }
+ if (this.Calendar.GetType() != typeof(JapaneseCalendar))
+ {
+ // Special case for Japanese. If this is a Japanese DTFI, and the calendar is not Japanese calendar,
+ // we will check Japanese Era name as well when the calendar is Gregorian.
+ DateTimeFormatInfo jaDtfi = GetJapaneseCalendarDTFI();
+ for (int i = 1; i <= jaDtfi.Calendar.Eras.Length; i++)
+ {
+ InsertHash(temp, jaDtfi.GetEraName(i), TokenType.JapaneseEraToken, i);
+ InsertHash(temp, jaDtfi.GetAbbreviatedEraName(i), TokenType.JapaneseEraToken, i);
+ // m_abbrevEnglishEraNames[0] contains the name for era 1, so the token value is i+1.
+ InsertHash(temp, jaDtfi.AbbreviatedEnglishEraNames[i - 1], TokenType.JapaneseEraToken, i);
+ }
+ }
+ }
+ // TODO: This prohibits similar custom cultures, but we hard coded the name
+ else if (CultureName.Equals("zh-TW"))
+ {
+ DateTimeFormatInfo twDtfi = GetTaiwanCalendarDTFI();
+ for (int i = 1; i <= twDtfi.Calendar.Eras.Length; i++)
+ {
+ if (twDtfi.GetEraName(i).Length > 0)
+ {
+ InsertHash(temp, twDtfi.GetEraName(i), TokenType.TEraToken, i);
+ }
+ }
+ }
+
+ InsertHash(temp, InvariantInfo.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
+ InsertHash(temp, InvariantInfo.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
+
+ // Add invariant month names and day names.
+ for (int i = 1; i <= 12; i++)
+ {
+ String str;
+ // We have to call public methods here to work with inherited DTFI.
+ // Insert the month name first, so that they are at the front of abbrevaited
+ // month names.
+ str = InvariantInfo.GetMonthName(i);
+ InsertHash(temp, str, TokenType.MonthToken, i);
+ str = InvariantInfo.GetAbbreviatedMonthName(i);
+ InsertHash(temp, str, TokenType.MonthToken, i);
+ }
+
+ for (int i = 0; i < 7; i++)
+ {
+ // We have to call public methods here to work with inherited DTFI.
+ String str = InvariantInfo.GetDayName((DayOfWeek)i);
+ InsertHash(temp, str, TokenType.DayOfWeekToken, i);
+
+ str = InvariantInfo.GetAbbreviatedDayName((DayOfWeek)i);
+ InsertHash(temp, str, TokenType.DayOfWeekToken, i);
+ }
+
+ for (int i = 0; i < AbbreviatedEnglishEraNames.Length; i++)
+ {
+ // m_abbrevEnglishEraNames[0] contains the name for era 1, so the token value is i+1.
+ InsertHash(temp, AbbreviatedEnglishEraNames[i], TokenType.EraToken, i + 1);
+ }
+
+ InsertHash(temp, LocalTimeMark, TokenType.SEP_LocalTimeMark, 0);
+ InsertHash(temp, GMTName, TokenType.TimeZoneToken, 0);
+ InsertHash(temp, ZuluName, TokenType.TimeZoneToken, 0);
+
+ InsertHash(temp, invariantDateSeparator, TokenType.SEP_Date, 0);
+ InsertHash(temp, invariantTimeSeparator, TokenType.SEP_Time, 0);
+
+ _dtfiTokenHash = temp;
+ }
+ return (temp);
+ }
+
+ private void AddMonthNames(TokenHashValue[] temp, String monthPostfix)
+ {
+ for (int i = 1; i <= 13; i++)
+ {
+ String str;
+ //str = internalGetMonthName(i, MonthNameStyles.Regular, false);
+ // We have to call public methods here to work with inherited DTFI.
+ // Insert the month name first, so that they are at the front of abbrevaited
+ // month names.
+ str = GetMonthName(i);
+ if (str.Length > 0)
+ {
+ if (monthPostfix != null)
+ {
+ // Insert the month name with the postfix first, so it can be matched first.
+ InsertHash(temp, str + monthPostfix, TokenType.MonthToken, i);
+ }
+ else
+ {
+ InsertHash(temp, str, TokenType.MonthToken, i);
+ }
+ }
+ str = GetAbbreviatedMonthName(i);
+ InsertHash(temp, str, TokenType.MonthToken, i);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Actions:
+ // Try to parse the current word to see if it is a Hebrew number.
+ // Tokens will be updated accordingly.
+ // This is called by the Lexer of DateTime.Parse().
+ //
+ // Unlike most of the functions in this class, the return value indicates
+ // whether or not it started to parse. The badFormat parameter indicates
+ // if parsing began, but the format was bad.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ private static bool TryParseHebrewNumber(
+#if INSIDE_CLR
+ ref __DTString str,
+#else
+ ref FormatProvider.__DTString str,
+#endif
+ out Boolean badFormat,
+ out int number)
+ {
+ number = -1;
+ badFormat = false;
+
+ int i = str.Index;
+ if (!HebrewNumber.IsDigit(str.Value[i]))
+ {
+ // If the current character is not a Hebrew digit, just return false.
+ // There is no chance that we can parse a valid Hebrew number from here.
+ return (false);
+ }
+ // The current character is a Hebrew digit. Try to parse this word as a Hebrew number.
+ HebrewNumberParsingContext context = new HebrewNumberParsingContext(0);
+ HebrewNumberParsingState state;
+
+ do
+ {
+ state = HebrewNumber.ParseByChar(str.Value[i++], ref context);
+ switch (state)
+ {
+ case HebrewNumberParsingState.InvalidHebrewNumber: // Not a valid Hebrew number.
+ case HebrewNumberParsingState.NotHebrewDigit: // The current character is not a Hebrew digit character.
+ // Break out so that we don't continue to try parse this as a Hebrew number.
+ return (false);
+ }
+ } while (i < str.Value.Length && (state != HebrewNumberParsingState.FoundEndOfHebrewNumber));
+
+ // When we are here, we are either at the end of the string, or we find a valid Hebrew number.
+ Contract.Assert(state == HebrewNumberParsingState.ContinueParsing || state == HebrewNumberParsingState.FoundEndOfHebrewNumber,
+ "Invalid returned state from HebrewNumber.ParseByChar()");
+
+ if (state != HebrewNumberParsingState.FoundEndOfHebrewNumber)
+ {
+ // We reach end of the string but we can't find a terminal state in parsing Hebrew number.
+ return (false);
+ }
+
+ // We have found a valid Hebrew number. Update the index.
+ str.Advance(i - str.Index);
+
+ // Get the final Hebrew number value from the HebrewNumberParsingContext.
+ number = context.result;
+
+ return (true);
+ }
+
+ private static bool IsHebrewChar(char ch)
+ {
+ return (ch >= '\x0590' && ch <= '\x05ff');
+ }
+
+ internal bool Tokenize(TokenType TokenMask, out TokenType tokenType, out int tokenValue,
+#if INSIDE_CLR
+ ref __DTString str)
+#else
+ ref FormatProvider.__DTString str)
+#endif
+
+ {
+ tokenType = TokenType.UnknownToken;
+ tokenValue = 0;
+
+ TokenHashValue value;
+ Contract.Assert(str.Index < str.Value.Length, "DateTimeFormatInfo.Tokenize(): start < value.Length");
+
+ char ch = str.m_current;
+ bool isLetter = Char.IsLetter(ch);
+ if (isLetter)
+ {
+ ch = this.Culture.TextInfo.ToLower(ch);
+ if (IsHebrewChar(ch) && TokenMask == TokenType.RegularTokenMask)
+ {
+ bool badFormat;
+ if (TryParseHebrewNumber(ref str, out badFormat, out tokenValue))
+ {
+ if (badFormat)
+ {
+ tokenType = TokenType.UnknownToken;
+ return (false);
+ }
+ // This is a Hebrew number.
+ // Do nothing here. TryParseHebrewNumber() will update token accordingly.
+ tokenType = TokenType.HebrewNumber;
+ return (true);
+ }
+ }
+ }
+
+
+ int hashcode = ch % TOKEN_HASH_SIZE;
+ int hashProbe = 1 + ch % SECOND_PRIME;
+ int remaining = str.len - str.Index;
+ int i = 0;
+
+ TokenHashValue[] hashTable = _dtfiTokenHash;
+ if (hashTable == null)
+ {
+ hashTable = CreateTokenHashTable();
+ }
+ do
+ {
+ value = hashTable[hashcode];
+ if (value == null)
+ {
+ // Not found.
+ break;
+ }
+ // Check this value has the right category (regular token or separator token) that we are looking for.
+ if (((int)value.tokenType & (int)TokenMask) > 0 && value.tokenString.Length <= remaining)
+ {
+ bool compareStrings = true;
+ if (isLetter)
+ {
+ // If this token starts with a letter, make sure that we won't allow partial match. So you can't tokenize "MarchWed" separately.
+ // Also an optimization to avoid string comparison
+ int nextCharIndex = str.Index + value.tokenString.Length;
+ if (nextCharIndex > str.len)
+ {
+ compareStrings = false;
+ }
+ else if (nextCharIndex < str.len)
+ {
+ // Check word boundary. The next character should NOT be a letter.
+ char nextCh = str.Value[nextCharIndex];
+ compareStrings = !(Char.IsLetter(nextCh));
+ }
+ }
+ if (compareStrings && CompareStringIgnoreCaseOptimized(str.Value, str.Index, value.tokenString.Length, value.tokenString, 0, value.tokenString.Length))
+ {
+ tokenType = value.tokenType & TokenMask;
+ tokenValue = value.tokenValue;
+ str.Advance(value.tokenString.Length);
+ return (true);
+ }
+ else if ((value.tokenType == TokenType.MonthToken && HasSpacesInMonthNames) ||
+ (value.tokenType == TokenType.DayOfWeekToken && HasSpacesInDayNames))
+ {
+ // For month or day token, we will match the names which have spaces.
+ int matchStrLen = 0;
+ if (str.MatchSpecifiedWords(value.tokenString, true, ref matchStrLen))
+ {
+ tokenType = value.tokenType & TokenMask;
+ tokenValue = value.tokenValue;
+ str.Advance(matchStrLen);
+ return (true);
+ }
+ }
+ }
+ i++;
+ hashcode += hashProbe;
+ if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE;
+ } while (i < TOKEN_HASH_SIZE);
+
+ return (false);
+ }
+
+ private void InsertAtCurrentHashNode(TokenHashValue[] hashTable, String str, char ch, TokenType tokenType, int tokenValue, int pos, int hashcode, int hashProbe)
+ {
+ // Remember the current slot.
+ TokenHashValue previousNode = hashTable[hashcode];
+
+ //// Console.WriteLine(" Insert Key: {0} in {1}", str, slotToInsert);
+ // Insert the new node into the current slot.
+ hashTable[hashcode] = new TokenHashValue(str, tokenType, tokenValue); ;
+
+ while (++pos < TOKEN_HASH_SIZE)
+ {
+ hashcode += hashProbe;
+ if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE;
+ // Remember this slot
+ TokenHashValue temp = hashTable[hashcode];
+
+ if (temp != null && this.Culture.TextInfo.ToLower(temp.tokenString[0]) != ch)
+ {
+ continue;
+ }
+ // Put the previous slot into this slot.
+ hashTable[hashcode] = previousNode;
+ //// Console.WriteLine(" Move {0} to slot {1}", previousNode.tokenString, hashcode);
+ if (temp == null)
+ {
+ // Done
+ return;
+ }
+ previousNode = temp;
+ };
+ Contract.Assert(false, "The hashtable is full. This should not happen.");
+ }
+
+ private void InsertHash(TokenHashValue[] hashTable, String str, TokenType tokenType, int tokenValue)
+ {
+ // The month of the 13th month is allowed to be null, so make sure that we ignore null value here.
+ if (str == null || str.Length == 0)
+ {
+ return;
+ }
+ TokenHashValue value;
+ int i = 0;
+ // If there is whitespace characters in the beginning and end of the string, trim them since whitespaces are skipped by
+ // DateTime.Parse().
+ if (Char.IsWhiteSpace(str[0]) || Char.IsWhiteSpace(str[str.Length - 1]))
+ {
+ str = str.Trim(null); // Trim white space characters.
+ // Could have space for separators
+ if (str.Length == 0)
+ return;
+ }
+ char ch = this.Culture.TextInfo.ToLower(str[0]);
+ int hashcode = ch % TOKEN_HASH_SIZE;
+ int hashProbe = 1 + ch % SECOND_PRIME;
+ do
+ {
+ value = hashTable[hashcode];
+ if (value == null)
+ {
+ //// Console.WriteLine(" Put Key: {0} in {1}", str, hashcode);
+ hashTable[hashcode] = new TokenHashValue(str, tokenType, tokenValue);
+ return;
+ }
+ else
+ {
+ // Collision happens. Find another slot.
+ if (str.Length >= value.tokenString.Length)
+ {
+ // If there are two tokens with the same prefix, we have to make sure that the longer token should be at the front of
+ // the shorter ones.
+ if (this.CompareStringIgnoreCaseOptimized(str, 0, value.tokenString.Length, value.tokenString, 0, value.tokenString.Length))
+ {
+ if (str.Length > value.tokenString.Length)
+ {
+ // The str to be inserted has the same prefix as the current token, and str is longer.
+ // Insert str into this node, and shift every node behind it.
+ InsertAtCurrentHashNode(hashTable, str, ch, tokenType, tokenValue, i, hashcode, hashProbe);
+ return;
+ }
+ else
+ {
+ // Same token. If they have different types (regular token vs separator token). Add them.
+ // If we have the same regular token or separator token in the hash already, do NOT update the hash.
+ // Therefore, the order of inserting token is significant here regarding what tokenType will be kept in the hash.
+
+
+ //
+ // Check the current value of RegularToken (stored in the lower 8-bit of tokenType) , and insert the tokenType into the hash ONLY when we don't have a RegularToken yet.
+ // Also check the current value of SeparatorToken (stored in the upper 8-bit of token), and insert the tokenType into the hash ONLY when we don't have the SeparatorToken yet.
+ //
+
+ int nTokenType = (int)tokenType;
+ int nCurrentTokenTypeInHash = (int)value.tokenType;
+
+ //
+ // The folowing is the fix for the issue of throwing FormatException when "mar" is passed in string of the short date format dd/MMM/yyyy for es-MX
+ //
+
+ if (((nCurrentTokenTypeInHash & (int)TokenType.RegularTokenMask) == 0) && ((nTokenType & (int)TokenType.RegularTokenMask) != 0) ||
+ ((nCurrentTokenTypeInHash & (int)TokenType.SeparatorTokenMask) == 0) && ((nTokenType & (int)TokenType.SeparatorTokenMask) != 0))
+ {
+ value.tokenType |= tokenType;
+ if (tokenValue != 0)
+ {
+ value.tokenValue = tokenValue;
+ }
+ }
+ // The token to be inserted is already in the table. Skip it.
+ return;
+ }
+ }
+ }
+ }
+ //// Console.WriteLine(" COLLISION. Old Key: {0}, New Key: {1}", hashTable[hashcode].tokenString, str);
+ i++;
+ hashcode += hashProbe;
+ if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE;
+ } while (i < TOKEN_HASH_SIZE);
+ Contract.Assert(false, "The hashtable is full. This should not happen.");
+ }
+
+ private bool CompareStringIgnoreCaseOptimized(string string1, int offset1, int length1, string string2, int offset2, int length2)
+ {
+ // Optimize for one character cases which are common due to date and time separators (/ and :)
+ if (length1 == 1 && length2 == 1 && string1[offset1] == string2[offset2])
+ {
+ return true;
+ }
+
+ return (this.Culture.CompareInfo.Compare(string1, offset1, length1, string2, offset2, length2, CompareOptions.IgnoreCase) == 0);
+ }
+
+ // class DateTimeFormatInfo
+
+ internal class TokenHashValue
+ {
+ internal String tokenString;
+ internal TokenType tokenType;
+ internal int tokenValue;
+
+ internal TokenHashValue(String tokenString, TokenType tokenType, int tokenValue)
+ {
+ this.tokenString = tokenString;
+ this.tokenType = tokenType;
+ this.tokenValue = tokenValue;
+ }
+ }
+ }
+
+#if !INSIDE_CLR
+ //
+ // The type of token that will be returned by DateTimeFormatInfo.Tokenize().
+ //
+ internal enum TokenType
+ {
+ // The valid token should start from 1.
+
+ // Regular tokens. The range is from 0x00 ~ 0xff.
+ NumberToken = 1, // The number. E.g. "12"
+ YearNumberToken = 2, // The number which is considered as year number, which has 3 or more digits. E.g. "2003"
+ Am = 3, // AM timemark. E.g. "AM"
+ Pm = 4, // PM timemark. E.g. "PM"
+ MonthToken = 5, // A word (or words) that represents a month name. E.g. "March"
+ EndOfString = 6, // End of string
+ DayOfWeekToken = 7, // A word (or words) that represents a day of week name. E.g. "Monday" or "Mon"
+ TimeZoneToken = 8, // A word that represents a timezone name. E.g. "GMT"
+ EraToken = 9, // A word that represents a era name. E.g. "A.D."
+ DateWordToken = 10, // A word that can appear in a DateTime string, but serves no parsing semantics. E.g. "de" in Spanish culture.
+ UnknownToken = 11, // An unknown word, which signals an error in parsing.
+ HebrewNumber = 12, // A number that is composed of Hebrew text. Hebrew calendar uses Hebrew digits for year values, month values, and day values.
+ JapaneseEraToken = 13, // Era name for JapaneseCalendar
+ TEraToken = 14, // Era name for TaiwanCalendar
+ IgnorableSymbol = 15, // A separator like "," that is equivalent to whitespace
+
+
+ // Separator tokens.
+ SEP_Unk = 0x100, // Unknown separator.
+ SEP_End = 0x200, // The end of the parsing string.
+ SEP_Space = 0x300, // Whitespace (including comma).
+ SEP_Am = 0x400, // AM timemark. E.g. "AM"
+ SEP_Pm = 0x500, // PM timemark. E.g. "PM"
+ SEP_Date = 0x600, // date separator. E.g. "/"
+ SEP_Time = 0x700, // time separator. E.g. ":"
+ SEP_YearSuff = 0x800, // Chinese/Japanese/Korean year suffix.
+ SEP_MonthSuff = 0x900, // Chinese/Japanese/Korean month suffix.
+ SEP_DaySuff = 0xa00, // Chinese/Japanese/Korean day suffix.
+ SEP_HourSuff = 0xb00, // Chinese/Japanese/Korean hour suffix.
+ SEP_MinuteSuff = 0xc00, // Chinese/Japanese/Korean minute suffix.
+ SEP_SecondSuff = 0xd00, // Chinese/Japanese/Korean second suffix.
+ SEP_LocalTimeMark = 0xe00, // 'T', used in ISO 8601 format.
+ SEP_DateOrOffset = 0xf00, // '-' which could be a date separator or start of a time zone offset
+
+ RegularTokenMask = 0x00ff,
+ SeparatorTokenMask = 0xff00,
+ }
+#endif
+
+}
diff --git a/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfoScanner.cs b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfoScanner.cs
new file mode 100644
index 0000000000..9cbc19f385
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfoScanner.cs
@@ -0,0 +1,742 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+// DateTimeFormatInfoScanner
+//
+// Scan a specified DateTimeFormatInfo to search for data used in DateTime.Parse()
+//
+// The data includes:
+//
+// DateWords: such as "de" used in es-ES (Spanish) LongDatePattern.
+// Postfix: such as "ta" used in fi-FI after the month name.
+//
+// This class is shared among mscorlib.dll and sysglobl.dll.
+// Use conditional CULTURE_AND_REGIONINFO_BUILDER_ONLY to differentiate between
+// methods for mscorlib.dll and sysglobl.dll.
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Globalization;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using StringStringDictionary = Dictionary<string, string>;
+ using StringList = List<string>;
+#else
+ using StringStringDictionary = LowLevelDictionary<string, string>;
+ using StringList = LowLevelList<string>;
+#endif
+
+ //
+ // from LocaleEx.txt header
+ //
+ //; IFORMATFLAGS
+ //; Parsing/formatting flags.
+ internal enum FORMATFLAGS
+ {
+ None = 0x00000000,
+ UseGenitiveMonth = 0x00000001,
+ UseLeapYearMonth = 0x00000002,
+ UseSpacesInMonthNames = 0x00000004,
+ UseHebrewParsing = 0x00000008,
+ UseSpacesInDayNames = 0x00000010, // Has spaces or non-breaking space in the day names.
+ UseDigitPrefixInTokens = 0x00000020, // Has token starting with numbers.
+ }
+
+ internal enum CalendarId : ushort
+ {
+ UNINITIALIZED_VALUE = 0,
+ GREGORIAN = 1, // Gregorian (localized) calendar
+ GREGORIAN_US = 2, // Gregorian (U.S.) calendar
+ JAPAN = 3, // Japanese Emperor Era calendar
+ /* SSS_WARNINGS_OFF */
+ TAIWAN = 4, // Taiwan Era calendar /* SSS_WARNINGS_ON */
+ KOREA = 5, // Korean Tangun Era calendar
+ HIJRI = 6, // Hijri (Arabic Lunar) calendar
+ THAI = 7, // Thai calendar
+ HEBREW = 8, // Hebrew (Lunar) calendar
+ GREGORIAN_ME_FRENCH = 9, // Gregorian Middle East French calendar
+ GREGORIAN_ARABIC = 10, // Gregorian Arabic calendar
+ GREGORIAN_XLIT_ENGLISH = 11, // Gregorian Transliterated English calendar
+ GREGORIAN_XLIT_FRENCH = 12,
+ // Note that all calendars after this point are MANAGED ONLY for now.
+ JULIAN = 13,
+ JAPANESELUNISOLAR = 14,
+ CHINESELUNISOLAR = 15,
+ SAKA = 16, // reserved to match Office but not implemented in our code
+ LUNAR_ETO_CHN = 17, // reserved to match Office but not implemented in our code
+ LUNAR_ETO_KOR = 18, // reserved to match Office but not implemented in our code
+ LUNAR_ETO_ROKUYOU = 19, // reserved to match Office but not implemented in our code
+ KOREANLUNISOLAR = 20,
+ TAIWANLUNISOLAR = 21,
+ PERSIAN = 22,
+ UMALQURA = 23,
+ LAST_CALENDAR = 23 // Last calendar ID
+ }
+
+ internal class DateTimeFormatInfoScanner
+ {
+ // Special prefix-like flag char in DateWord array.
+
+ // Use char in PUA area since we won't be using them in real data.
+ // The char used to tell a read date word or a month postfix. A month postfix
+ // is "ta" in the long date pattern like "d. MMMM'ta 'yyyy" for fi-FI.
+ // In this case, it will be stored as "\xfffeta" in the date word array.
+ internal const char MonthPostfixChar = '\xe000';
+
+ // Add ignorable symbol in a DateWord array.
+
+ // hu-HU has:
+ // shrot date pattern: yyyy. MM. dd.;yyyy-MM-dd;yy-MM-dd
+ // long date pattern: yyyy. MMMM d.
+ // Here, "." is the date separator (derived from short date pattern). However,
+ // "." also appear at the end of long date pattern. In this case, we just
+ // "." as ignorable symbol so that the DateTime.Parse() state machine will not
+ // treat the additional date separator at the end of y,m,d pattern as an error
+ // condition.
+ internal const char IgnorableSymbolChar = '\xe001';
+
+ // Known CJK suffix
+ internal const String CJKYearSuff = "\u5e74";
+ internal const String CJKMonthSuff = "\u6708";
+ internal const String CJKDaySuff = "\u65e5";
+
+ internal const String KoreanYearSuff = "\ub144";
+ internal const String KoreanMonthSuff = "\uc6d4";
+ internal const String KoreanDaySuff = "\uc77c";
+
+ internal const String KoreanHourSuff = "\uc2dc";
+ internal const String KoreanMinuteSuff = "\ubd84";
+ internal const String KoreanSecondSuff = "\ucd08";
+
+ internal const String CJKHourSuff = "\u6642";
+ internal const String ChineseHourSuff = "\u65f6";
+
+ internal const String CJKMinuteSuff = "\u5206";
+ internal const String CJKSecondSuff = "\u79d2";
+
+ // The collection fo date words & postfix.
+ internal StringList m_dateWords = new StringList();
+ // Hashtable for the known words.
+ private static volatile StringStringDictionary s_knownWords;
+
+ static StringStringDictionary KnownWords
+ {
+ get
+ {
+ if (s_knownWords == null)
+ {
+ StringStringDictionary temp = new StringStringDictionary();
+ // Add known words into the hash table.
+
+ // Skip these special symbols.
+ temp.Add("/", String.Empty);
+ temp.Add("-", String.Empty);
+ temp.Add(".", String.Empty);
+ // Skip known CJK suffixes.
+ temp.Add(CJKYearSuff, String.Empty);
+ temp.Add(CJKMonthSuff, String.Empty);
+ temp.Add(CJKDaySuff, String.Empty);
+ temp.Add(KoreanYearSuff, String.Empty);
+ temp.Add(KoreanMonthSuff, String.Empty);
+ temp.Add(KoreanDaySuff, String.Empty);
+ temp.Add(KoreanHourSuff, String.Empty);
+ temp.Add(KoreanMinuteSuff, String.Empty);
+ temp.Add(KoreanSecondSuff, String.Empty);
+ temp.Add(CJKHourSuff, String.Empty);
+ temp.Add(ChineseHourSuff, String.Empty);
+ temp.Add(CJKMinuteSuff, String.Empty);
+ temp.Add(CJKSecondSuff, String.Empty);
+
+ s_knownWords = temp;
+ }
+ return (s_knownWords);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Parameters:
+ // pattern: The pattern to be scanned.
+ // currentIndex: the current index to start the scan.
+ //
+ // Returns:
+ // Return the index with the first character that is a letter, which will
+ // be the start of a date word.
+ // Note that the index can be pattern.Length if we reach the end of the string.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal static int SkipWhiteSpacesAndNonLetter(String pattern, int currentIndex)
+ {
+ while (currentIndex < pattern.Length)
+ {
+ char ch = pattern[currentIndex];
+ if (ch == '\\')
+ {
+ // Escaped character. Look ahead one character.
+ currentIndex++;
+ if (currentIndex < pattern.Length)
+ {
+ ch = pattern[currentIndex];
+ if (ch == '\'')
+ {
+ // Skip the leading single quote. We will
+ // stop at the first letter.
+ continue;
+ }
+ // Fall thru to check if this is a letter.
+ }
+ else
+ {
+ // End of string
+ break;
+ }
+ }
+ if (Char.IsLetter(ch) || ch == '\'' || ch == '.')
+ {
+ break;
+ }
+ // Skip the current char since it is not a letter.
+ currentIndex++;
+ }
+ return (currentIndex);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // A helper to add the found date word or month postfix into ArrayList for date words.
+ //
+ // Parameters:
+ // formatPostfix: What kind of postfix this is.
+ // Possible values:
+ // null: This is a regular date word
+ // "MMMM": month postfix
+ // word: The date word or postfix to be added.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal void AddDateWordOrPostfix(String formatPostfix, String str)
+ {
+ if (str.Length > 0)
+ {
+ // Some cultures use . like an abbreviation
+ if (str.Equals("."))
+ {
+ AddIgnorableSymbols(".");
+ return;
+ }
+ String words;
+ if (KnownWords.TryGetValue(str, out words) == false)
+ {
+ if (m_dateWords == null)
+ {
+ m_dateWords = new StringList();
+ }
+ if (formatPostfix == "MMMM")
+ {
+ // Add the word into the ArrayList as "\xfffe" + real month postfix.
+ String temp = MonthPostfixChar + str;
+ if (!m_dateWords.Contains(temp))
+ {
+ m_dateWords.Add(temp);
+ }
+ }
+ else
+ {
+ if (!m_dateWords.Contains(str))
+ {
+ m_dateWords.Add(str);
+ }
+ if (str[str.Length - 1] == '.')
+ {
+ // Old version ignore the trialing dot in the date words. Support this as well.
+ String strWithoutDot = str.Substring(0, str.Length - 1);
+ if (!m_dateWords.Contains(strWithoutDot))
+ {
+ m_dateWords.Add(strWithoutDot);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Scan the pattern from the specified index and add the date word/postfix
+ // when appropriate.
+ //
+ // Parameters:
+ // pattern: The pattern to be scanned.
+ // index: The starting index to be scanned.
+ // formatPostfix: The kind of postfix to be scanned.
+ // Possible values:
+ // null: This is a regular date word
+ // "MMMM": month postfix
+ //
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal int AddDateWords(String pattern, int index, String formatPostfix)
+ {
+ // Skip any whitespaces so we will start from a letter.
+ int newIndex = SkipWhiteSpacesAndNonLetter(pattern, index);
+ if (newIndex != index && formatPostfix != null)
+ {
+ // There are whitespaces. This will not be a postfix.
+ formatPostfix = null;
+ }
+ index = newIndex;
+
+ // This is the first char added into dateWord.
+ // Skip all non-letter character. We will add the first letter into DateWord.
+ StringBuilder dateWord = new StringBuilder();
+ // We assume that date words should start with a letter.
+ // Skip anything until we see a letter.
+
+ while (index < pattern.Length)
+ {
+ char ch = pattern[index];
+ if (ch == '\'')
+ {
+ // We have seen the end of quote. Add the word if we do not see it before,
+ // and break the while loop.
+ AddDateWordOrPostfix(formatPostfix, dateWord.ToString());
+ index++;
+ break;
+ }
+ else if (ch == '\\')
+ {
+ //
+ // Escaped character. Look ahead one character
+ //
+
+ // Skip escaped backslash.
+ index++;
+ if (index < pattern.Length)
+ {
+ dateWord.Append(pattern[index]);
+ index++;
+ }
+ }
+ else if (Char.IsWhiteSpace(ch))
+ {
+ // Found a whitespace. We have to add the current date word/postfix.
+ AddDateWordOrPostfix(formatPostfix, dateWord.ToString());
+ if (formatPostfix != null)
+ {
+ // Done with postfix. The rest will be regular date word.
+ formatPostfix = null;
+ }
+ // Reset the dateWord.
+ dateWord.Length = 0;
+ index++;
+ }
+ else
+ {
+ dateWord.Append(ch);
+ index++;
+ }
+ }
+ return (index);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // A simple helper to find the repeat count for a specified char.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal static int ScanRepeatChar(String pattern, char ch, int index, out int count)
+ {
+ count = 1;
+ while (++index < pattern.Length && pattern[index] == ch)
+ {
+ count++;
+ }
+ // Return the updated position.
+ return (index);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Add the text that is a date separator but is treated like ignroable symbol.
+ // E.g.
+ // hu-HU has:
+ // shrot date pattern: yyyy. MM. dd.;yyyy-MM-dd;yy-MM-dd
+ // long date pattern: yyyy. MMMM d.
+ // Here, "." is the date separator (derived from short date pattern). However,
+ // "." also appear at the end of long date pattern. In this case, we just
+ // "." as ignorable symbol so that the DateTime.Parse() state machine will not
+ // treat the additional date separator at the end of y,m,d pattern as an error
+ // condition.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal void AddIgnorableSymbols(String text)
+ {
+ if (m_dateWords == null)
+ {
+ // Create the date word array.
+ m_dateWords = new StringList();
+ }
+ // Add the ignorable symbol into the ArrayList.
+ String temp = IgnorableSymbolChar + text;
+ if (!m_dateWords.Contains(temp))
+ {
+ m_dateWords.Add(temp);
+ }
+ }
+
+
+ //
+ // Flag used to trace the date patterns (yy/yyyyy/M/MM/MMM/MMM/d/dd) that we have seen.
+ //
+ private enum FoundDatePattern
+ {
+ None = 0x0000,
+ FoundYearPatternFlag = 0x0001,
+ FoundMonthPatternFlag = 0x0002,
+ FoundDayPatternFlag = 0x0004,
+ FoundYMDPatternFlag = 0x0007, // FoundYearPatternFlag | FoundMonthPatternFlag | FoundDayPatternFlag;
+ }
+
+ // Check if we have found all of the year/month/day pattern.
+ private FoundDatePattern _ymdFlags = FoundDatePattern.None;
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Given a date format pattern, scan for date word or postfix.
+ //
+ // A date word should be always put in a single quoted string. And it will
+ // start from a letter, so whitespace and symbols will be ignored before
+ // the first letter.
+ //
+ // Examples of date word:
+ // 'de' in es-SP: dddd, dd' de 'MMMM' de 'yyyy
+ // "\x0443." in bg-BG: dd.M.yyyy '\x0433.'
+ //
+ // Example of postfix:
+ // month postfix:
+ // "ta" in fi-FI: d. MMMM'ta 'yyyy
+ // Currently, only month postfix is supported.
+ //
+ // Usage:
+ // Always call this with Framework-style pattern, instead of Windows style pattern.
+ // Windows style pattern uses '' for single quote, while .NET uses \'
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal void ScanDateWord(String pattern)
+ {
+ // Check if we have found all of the year/month/day pattern.
+ _ymdFlags = FoundDatePattern.None;
+
+ int i = 0;
+ while (i < pattern.Length)
+ {
+ char ch = pattern[i];
+ int chCount;
+
+ switch (ch)
+ {
+ case '\'':
+ // Find a beginning quote. Search until the end quote.
+ i = AddDateWords(pattern, i + 1, null);
+ break;
+ case 'M':
+ i = ScanRepeatChar(pattern, 'M', i, out chCount);
+ if (chCount >= 4)
+ {
+ if (i < pattern.Length && pattern[i] == '\'')
+ {
+ i = AddDateWords(pattern, i + 1, "MMMM");
+ }
+ }
+ _ymdFlags |= FoundDatePattern.FoundMonthPatternFlag;
+ break;
+ case 'y':
+ i = ScanRepeatChar(pattern, 'y', i, out chCount);
+ _ymdFlags |= FoundDatePattern.FoundYearPatternFlag;
+ break;
+ case 'd':
+ i = ScanRepeatChar(pattern, 'd', i, out chCount);
+ if (chCount <= 2)
+ {
+ // Only count "d" & "dd".
+ // ddd, dddd are day names. Do not count them.
+ _ymdFlags |= FoundDatePattern.FoundDayPatternFlag;
+ }
+ break;
+ case '\\':
+ // Found a escaped char not in a quoted string. Skip the current backslash
+ // and its next character.
+ i += 2;
+ break;
+ case '.':
+ if (_ymdFlags == FoundDatePattern.FoundYMDPatternFlag)
+ {
+ // If we find a dot immediately after the we have seen all of the y, m, d pattern.
+ // treat it as a ignroable symbol. Check for comments in AddIgnorableSymbols for
+ // more details.
+ AddIgnorableSymbols(".");
+ _ymdFlags = FoundDatePattern.None;
+ }
+ i++;
+ break;
+ default:
+ if (_ymdFlags == FoundDatePattern.FoundYMDPatternFlag && !Char.IsWhiteSpace(ch))
+ {
+ // We are not seeing "." after YMD. Clear the flag.
+ _ymdFlags = FoundDatePattern.None;
+ }
+ // We are not in quote. Skip the current character.
+ i++;
+ break;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Given a DTFI, get all of the date words from date patterns and time patterns.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal String[] GetDateWordsOfDTFI(DateTimeFormatInfo dtfi)
+ {
+ // Enumarate all LongDatePatterns, and get the DateWords and scan for month postfix.
+ String[] datePatterns = dtfi.GetAllDateTimePatterns('D');
+ int i;
+
+ // Scan the long date patterns
+ for (i = 0; i < datePatterns.Length; i++)
+ {
+ ScanDateWord(datePatterns[i]);
+ }
+
+ // Scan the short date patterns
+ datePatterns = dtfi.GetAllDateTimePatterns('d');
+ for (i = 0; i < datePatterns.Length; i++)
+ {
+ ScanDateWord(datePatterns[i]);
+ }
+ // Scan the YearMonth patterns.
+ datePatterns = dtfi.GetAllDateTimePatterns('y');
+ for (i = 0; i < datePatterns.Length; i++)
+ {
+ ScanDateWord(datePatterns[i]);
+ }
+
+ // Scan the month/day pattern
+ ScanDateWord(dtfi.MonthDayPattern);
+
+ // Scan the long time patterns.
+ datePatterns = dtfi.GetAllDateTimePatterns('T');
+ for (i = 0; i < datePatterns.Length; i++)
+ {
+ ScanDateWord(datePatterns[i]);
+ }
+
+ // Scan the short time patterns.
+ datePatterns = dtfi.GetAllDateTimePatterns('t');
+ for (i = 0; i < datePatterns.Length; i++)
+ {
+ ScanDateWord(datePatterns[i]);
+ }
+
+ String[] result = null;
+ if (m_dateWords != null && m_dateWords.Count > 0)
+ {
+ result = new String[m_dateWords.Count];
+ for (i = 0; i < m_dateWords.Count; i++)
+ {
+ result[i] = m_dateWords[i];
+ }
+ }
+ return (result);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Scan the month names to see if genitive month names are used, and return
+ // the format flag.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal static FORMATFLAGS GetFormatFlagGenitiveMonth(String[] monthNames, String[] genitveMonthNames, String[] abbrevMonthNames, String[] genetiveAbbrevMonthNames)
+ {
+ // If we have different names in regular and genitive month names, use genitive month flag.
+ return ((!EqualStringArrays(monthNames, genitveMonthNames) || !EqualStringArrays(abbrevMonthNames, genetiveAbbrevMonthNames))
+ ? FORMATFLAGS.UseGenitiveMonth : 0);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Scan the month names to see if spaces are used or start with a digit, and return the format flag
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal static FORMATFLAGS GetFormatFlagUseSpaceInMonthNames(String[] monthNames, String[] genitveMonthNames, String[] abbrevMonthNames, String[] genetiveAbbrevMonthNames)
+ {
+ FORMATFLAGS formatFlags = 0;
+ formatFlags |= (ArrayElementsBeginWithDigit(monthNames) ||
+ ArrayElementsBeginWithDigit(genitveMonthNames) ||
+ ArrayElementsBeginWithDigit(abbrevMonthNames) ||
+ ArrayElementsBeginWithDigit(genetiveAbbrevMonthNames)
+ ? FORMATFLAGS.UseDigitPrefixInTokens : 0);
+
+ formatFlags |= (ArrayElementsHaveSpace(monthNames) ||
+ ArrayElementsHaveSpace(genitveMonthNames) ||
+ ArrayElementsHaveSpace(abbrevMonthNames) ||
+ ArrayElementsHaveSpace(genetiveAbbrevMonthNames)
+ ? FORMATFLAGS.UseSpacesInMonthNames : 0);
+ return (formatFlags);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Scan the day names and set the correct format flag.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal static FORMATFLAGS GetFormatFlagUseSpaceInDayNames(String[] dayNames, String[] abbrevDayNames)
+ {
+ return ((ArrayElementsHaveSpace(dayNames) ||
+ ArrayElementsHaveSpace(abbrevDayNames))
+ ? FORMATFLAGS.UseSpacesInDayNames : 0);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Check the calendar to see if it is HebrewCalendar and set the Hebrew format flag if necessary.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ internal static FORMATFLAGS GetFormatFlagUseHebrewCalendar(int calID)
+ {
+ return (calID == (int)CalendarId.HEBREW ?
+ FORMATFLAGS.UseHebrewParsing | FORMATFLAGS.UseLeapYearMonth : 0);
+ }
+
+
+ //-----------------------------------------------------------------------------
+ // EqualStringArrays
+ // compares two string arrays and return true if all elements of the first
+ // array equals to all elmentsof the second array.
+ // otherwise it returns false.
+ //-----------------------------------------------------------------------------
+
+ private static bool EqualStringArrays(string[] array1, string[] array2)
+ {
+ // Shortcut if they're the same array
+ if (array1 == array2)
+ {
+ return true;
+ }
+
+ // This is effectively impossible
+ if (array1.Length != array2.Length)
+ {
+ return false;
+ }
+
+ // Check each string
+ for (int i = 0; i < array1.Length; i++)
+ {
+ if (!array1[i].Equals(array2[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //-----------------------------------------------------------------------------
+ // ArrayElementsHaveSpace
+ // It checks all input array elements if any of them has space character
+ // returns true if found space character in one of the array elements.
+ // otherwise returns false.
+ //-----------------------------------------------------------------------------
+
+ private static bool ArrayElementsHaveSpace(string[] array)
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ // it is faster to check for space character manually instead of calling IndexOf
+ // so we don't have to go to native code side.
+ for (int j = 0; j < array[i].Length; j++)
+ {
+ if (Char.IsWhiteSpace(array[i][j]))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Check if any element of the array start with a digit.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static bool ArrayElementsBeginWithDigit(string[] array)
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ // it is faster to check for space character manually instead of calling IndexOf
+ // so we don't have to go to native code side.
+ if (array[i].Length > 0 &&
+ array[i][0] >= '0' && array[i][0] <= '9')
+ {
+ int index = 1;
+ while (index < array[i].Length && array[i][index] >= '0' && array[i][index] <= '9')
+ {
+ // Skip other digits.
+ index++;
+ }
+ if (index == array[i].Length)
+ {
+ return (false);
+ }
+
+ if (index == array[i].Length - 1)
+ {
+ // Skip known CJK month suffix.
+ // CJK uses month name like "1\x6708", since \x6708 is a known month suffix,
+ // we don't need the UseDigitPrefixInTokens since it is slower.
+ switch (array[i][index])
+ {
+ case '\x6708': // CJKMonthSuff
+ case '\xc6d4': // KoreanMonthSuff
+ return (false);
+ }
+ }
+
+ if (index == array[i].Length - 4)
+ {
+ // Skip known CJK month suffix.
+ // Starting with Windows 8, the CJK months for some cultures looks like: "1' \x6708'"
+ // instead of just "1\x6708"
+ if (array[i][index] == '\'' && array[i][index + 1] == ' ' &&
+ array[i][index + 2] == '\x6708' && array[i][index + 3] == '\'')
+ {
+ return (false);
+ }
+ }
+ return (true);
+ }
+ }
+
+ return false;
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/DayLightTime.cs b/src/mscorlib/corefx/System/Globalization/DayLightTime.cs
new file mode 100644
index 0000000000..2345fb5bc2
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/DayLightTime.cs
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ // This class represents a starting/ending time for a period of daylight saving time.
+
+ [Serializable]
+ public partial class DaylightTime
+ {
+ internal DateTime m_start;
+ internal DateTime m_end;
+ internal TimeSpan m_delta;
+
+ private DaylightTime()
+ {
+ }
+
+ public DaylightTime(DateTime start, DateTime end, TimeSpan delta)
+ {
+ m_start = start;
+ m_end = end;
+ m_delta = delta;
+ }
+
+ // The start date of a daylight saving period.
+ public DateTime Start
+ {
+ get
+ {
+ return m_start;
+ }
+ }
+
+ // The end date of a daylight saving period.
+ public DateTime End
+ {
+ get
+ {
+ return m_end;
+ }
+ }
+
+ // Delta to stardard offset in ticks.
+ public TimeSpan Delta
+ {
+ get
+ {
+ return m_delta;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/EastAsianLunisolarCalendar.cs b/src/mscorlib/corefx/System/Globalization/EastAsianLunisolarCalendar.cs
new file mode 100644
index 0000000000..8f2bbbc10f
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/EastAsianLunisolarCalendar.cs
@@ -0,0 +1,719 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about EastAsianLunisolarCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public abstract class EastAsianLunisolarCalendar : Calendar
+ {
+ internal const int LeapMonth = 0;
+ internal const int Jan1Month = 1;
+ internal const int Jan1Date = 2;
+ internal const int nDaysPerMonth = 3;
+
+ // # of days so far in the solar year
+ internal static readonly int[] DaysToMonth365 =
+ {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+ };
+
+ internal static readonly int[] DaysToMonth366 =
+ {
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335
+ };
+
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+
+ // Return the type of the East Asian Lunisolar calendars.
+ //
+
+ //public override CalendarAlgorithmType AlgorithmType {
+ // get {
+ // return CalendarAlgorithmType.LunisolarCalendar;
+ // }
+ //}
+
+ // Return the year number in the 60-year cycle.
+ //
+
+ public virtual int GetSexagenaryYear(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+
+ int year = 0, month = 0, day = 0;
+ TimeToLunar(time, ref year, ref month, ref day);
+
+ return ((year - 4) % 60) + 1;
+ }
+
+ // Return the celestial year from the 60-year cycle.
+ // The returned value is from 1 ~ 10.
+ //
+
+ public int GetCelestialStem(int sexagenaryYear)
+ {
+ if ((sexagenaryYear < 1) || (sexagenaryYear > 60))
+ {
+ throw new ArgumentOutOfRangeException(
+ "sexagenaryYear",
+ SR.Format(SR.ArgumentOutOfRange_Range, 1, 60));
+ }
+ Contract.EndContractBlock();
+
+ return ((sexagenaryYear - 1) % 10) + 1;
+ }
+
+ // Return the Terrestial Branch from the the 60-year cycle.
+ // The returned value is from 1 ~ 12.
+ //
+
+ public int GetTerrestrialBranch(int sexagenaryYear)
+ {
+ if ((sexagenaryYear < 1) || (sexagenaryYear > 60))
+ {
+ throw new ArgumentOutOfRangeException(
+ "sexagenaryYear",
+ SR.Format(SR.ArgumentOutOfRange_Range, 1, 60));
+ }
+ Contract.EndContractBlock();
+
+ return ((sexagenaryYear - 1) % 12) + 1;
+ }
+
+ internal abstract int GetYearInfo(int LunarYear, int Index);
+ internal abstract int GetYear(int year, DateTime time);
+ internal abstract int GetGregorianYear(int year, int era);
+
+ internal abstract int MinCalendarYear { get; }
+ internal abstract int MaxCalendarYear { get; }
+ internal abstract EraInfo[] CalEraInfo { get; }
+ internal abstract DateTime MinDate { get; }
+ internal abstract DateTime MaxDate { get; }
+
+ internal const int MaxCalendarMonth = 13;
+ internal const int MaxCalendarDay = 30;
+
+ internal int MinEraCalendarYear(int era)
+ {
+ EraInfo[] mEraInfo = CalEraInfo;
+ //ChineseLunisolarCalendar does not has m_EraInfo it is going to retuen null
+ if (mEraInfo == null)
+ {
+ return MinCalendarYear;
+ }
+
+ if (era == Calendar.CurrentEra)
+ {
+ era = CurrentEraValue;
+ }
+ //era has to be in the supported range otherwise we will throw exception in CheckEraRange()
+ if (era == GetEra(MinDate))
+ {
+ return (GetYear(MinCalendarYear, MinDate));
+ }
+
+ for (int i = 0; i < mEraInfo.Length; i++)
+ {
+ if (era == mEraInfo[i].era)
+ {
+ return (mEraInfo[i].minEraYear);
+ }
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal int MaxEraCalendarYear(int era)
+ {
+ EraInfo[] mEraInfo = CalEraInfo;
+ //ChineseLunisolarCalendar does not has m_EraInfo it is going to retuen null
+ if (mEraInfo == null)
+ {
+ return MaxCalendarYear;
+ }
+
+ if (era == Calendar.CurrentEra)
+ {
+ era = CurrentEraValue;
+ }
+ //era has to be in the supported range otherwise we will throw exception in CheckEraRange()
+ if (era == GetEra(MaxDate))
+ {
+ return (GetYear(MaxCalendarYear, MaxDate));
+ }
+
+ for (int i = 0; i < mEraInfo.Length; i++)
+ {
+ if (era == mEraInfo[i].era)
+ {
+ return (mEraInfo[i].maxEraYear);
+ }
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal EastAsianLunisolarCalendar()
+ {
+ }
+
+ internal void CheckTicksRange(long ticks)
+ {
+ if (ticks < MinSupportedDateTime.Ticks || ticks > MaxSupportedDateTime.Ticks)
+ {
+ throw new ArgumentOutOfRangeException(
+ "time",
+ String.Format(CultureInfo.InvariantCulture, SR.ArgumentOutOfRange_CalendarRange,
+ MinSupportedDateTime, MaxSupportedDateTime));
+ }
+ Contract.EndContractBlock();
+ }
+
+ internal void CheckEraRange(int era)
+ {
+ if (era == Calendar.CurrentEra)
+ {
+ era = CurrentEraValue;
+ }
+
+ if ((era < GetEra(MinDate)) || (era > GetEra(MaxDate)))
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ }
+
+ internal int CheckYearRange(int year, int era)
+ {
+ CheckEraRange(era);
+ year = GetGregorianYear(year, era);
+
+ if ((year < MinCalendarYear) || (year > MaxCalendarYear))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ SR.Format(SR.ArgumentOutOfRange_Range, MinEraCalendarYear(era), MaxEraCalendarYear(era)));
+ }
+ return year;
+ }
+
+ internal int CheckYearMonthRange(int year, int month, int era)
+ {
+ year = CheckYearRange(year, era);
+
+ if (month == 13)
+ {
+ //Reject if there is no leap month this year
+ if (GetYearInfo(year, LeapMonth) == 0)
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+
+ if (month < 1 || month > 13)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ return year;
+ }
+
+ internal int InternalGetDaysInMonth(int year, int month)
+ {
+ int nDays;
+ int mask; // mask for extracting bits
+
+ mask = 0x8000;
+ // convert the lunar day into a lunar month/date
+ mask >>= (month - 1);
+ if ((GetYearInfo(year, nDaysPerMonth) & mask) == 0)
+ nDays = 29;
+ else
+ nDays = 30;
+ return nDays;
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ year = CheckYearMonthRange(year, month, era);
+ return InternalGetDaysInMonth(year, month);
+ }
+
+ private static int GregorianIsLeapYear(int y)
+ {
+ return ((((y) % 4) != 0) ? 0 : ((((y) % 100) != 0) ? 1 : ((((y) % 400) != 0) ? 0 : 1)));
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ year = CheckYearMonthRange(year, month, era);
+ int daysInMonth = InternalGetDaysInMonth(year, month);
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month));
+ }
+
+ int gy = 0; int gm = 0; int gd = 0;
+
+ if (LunarToGregorian(year, month, day, ref gy, ref gm, ref gd))
+ {
+ return new DateTime(gy, gm, gd, hour, minute, second, millisecond);
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+ }
+
+
+ //
+ // GregorianToLunar calculates lunar calendar info for the given gregorian year, month, date.
+ // The input date should be validated before calling this method.
+ //
+ internal void GregorianToLunar(int nSYear, int nSMonth, int nSDate, ref int nLYear, ref int nLMonth, ref int nLDate)
+ {
+ // unsigned int nLYear, nLMonth, nLDate; // lunar ymd
+ int nSolarDay; // day # in solar year
+ int nLunarDay; // day # in lunar year
+ int fLeap; // is it a solar leap year?
+ int LDpM; // lunar days/month bitfield
+ int mask; // mask for extracting bits
+ int nDays; // # days this lunar month
+ int nJan1Month, nJan1Date;
+
+ // calc the solar day of year
+ fLeap = GregorianIsLeapYear(nSYear);
+ nSolarDay = (fLeap == 1) ? DaysToMonth366[nSMonth - 1] : DaysToMonth365[nSMonth - 1];
+ nSolarDay += nSDate;
+
+ // init lunar year info
+ nLunarDay = nSolarDay;
+ nLYear = nSYear;
+ if (nLYear == (MaxCalendarYear + 1))
+ {
+ nLYear--;
+ nLunarDay += ((GregorianIsLeapYear(nLYear) == 1) ? 366 : 365);
+ nJan1Month = GetYearInfo(nLYear, Jan1Month);
+ nJan1Date = GetYearInfo(nLYear, Jan1Date);
+ }
+ else
+ {
+ nJan1Month = GetYearInfo(nLYear, Jan1Month);
+ nJan1Date = GetYearInfo(nLYear, Jan1Date);
+
+ // check if this solar date is actually part of the previous
+ // lunar year
+ if ((nSMonth < nJan1Month) ||
+ (nSMonth == nJan1Month && nSDate < nJan1Date))
+ {
+ // the corresponding lunar day is actually part of the previous
+ // lunar year
+ nLYear--;
+
+ // add a solar year to the lunar day #
+ nLunarDay += ((GregorianIsLeapYear(nLYear) == 1) ? 366 : 365);
+
+ // update the new start of year
+ nJan1Month = GetYearInfo(nLYear, Jan1Month);
+ nJan1Date = GetYearInfo(nLYear, Jan1Date);
+ }
+ }
+
+ // convert solar day into lunar day.
+ // subtract off the beginning part of the solar year which is not
+ // part of the lunar year. since this part is always in Jan or Feb,
+ // we don't need to handle Leap Year (LY only affects March
+ // and later).
+ nLunarDay -= DaysToMonth365[nJan1Month - 1];
+ nLunarDay -= (nJan1Date - 1);
+
+ // convert the lunar day into a lunar month/date
+ mask = 0x8000;
+ LDpM = GetYearInfo(nLYear, nDaysPerMonth);
+ nDays = ((LDpM & mask) != 0) ? 30 : 29;
+ nLMonth = 1;
+ while (nLunarDay > nDays)
+ {
+ nLunarDay -= nDays;
+ nLMonth++;
+ mask >>= 1;
+ nDays = ((LDpM & mask) != 0) ? 30 : 29;
+ }
+ nLDate = nLunarDay;
+ }
+
+ /*
+ //Convert from Lunar to Gregorian
+ //Highly inefficient, but it works based on the forward conversion
+ */
+ internal bool LunarToGregorian(int nLYear, int nLMonth, int nLDate, ref int nSolarYear, ref int nSolarMonth, ref int nSolarDay)
+ {
+ int numLunarDays;
+
+ if (nLDate < 1 || nLDate > 30)
+ return false;
+
+ numLunarDays = nLDate - 1;
+
+ //Add previous months days to form the total num of days from the first of the month.
+ for (int i = 1; i < nLMonth; i++)
+ {
+ numLunarDays += InternalGetDaysInMonth(nLYear, i);
+ }
+
+ //Get Gregorian First of year
+ int nJan1Month = GetYearInfo(nLYear, Jan1Month);
+ int nJan1Date = GetYearInfo(nLYear, Jan1Date);
+
+ // calc the solar day of year of 1 Lunar day
+ int fLeap = GregorianIsLeapYear(nLYear);
+ int[] days = (fLeap == 1) ? DaysToMonth366 : DaysToMonth365;
+
+ nSolarDay = nJan1Date;
+
+ if (nJan1Month > 1)
+ nSolarDay += days[nJan1Month - 1];
+
+ // Add the actual lunar day to get the solar day we want
+ nSolarDay = nSolarDay + numLunarDays;// - 1;
+
+ if (nSolarDay > (fLeap + 365))
+ {
+ nSolarYear = nLYear + 1;
+ nSolarDay -= (fLeap + 365);
+ }
+ else
+ {
+ nSolarYear = nLYear;
+ }
+
+ for (nSolarMonth = 1; nSolarMonth < 12; nSolarMonth++)
+ {
+ if (days[nSolarMonth] >= nSolarDay)
+ break;
+ }
+
+ nSolarDay -= days[nSolarMonth - 1];
+ return true;
+ }
+
+ internal DateTime LunarToTime(DateTime time, int year, int month, int day)
+ {
+ int gy = 0; int gm = 0; int gd = 0;
+ LunarToGregorian(year, month, day, ref gy, ref gm, ref gd);
+ return (GregorianCalendar.GetDefaultInstance().ToDateTime(gy, gm, gd, time.Hour, time.Minute, time.Second, time.Millisecond));
+ }
+
+ internal void TimeToLunar(DateTime time, ref int year, ref int month, ref int day)
+ {
+ int gy = 0; int gm = 0; int gd = 0;
+
+ Calendar Greg = GregorianCalendar.GetDefaultInstance();
+ gy = Greg.GetYear(time);
+ gm = Greg.GetMonth(time);
+ gd = Greg.GetDayOfMonth(time);
+
+ GregorianToLunar(gy, gm, gd, ref year, ref month, ref day);
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000));
+ }
+ Contract.EndContractBlock();
+
+ CheckTicksRange(time.Ticks);
+
+ int y = 0; int m = 0; int d = 0;
+ TimeToLunar(time, ref y, ref m, ref d);
+
+ int i = m + months;
+ if (i > 0)
+ {
+ int monthsInYear = InternalIsLeapYear(y) ? 13 : 12;
+
+ while (i - monthsInYear > 0)
+ {
+ i -= monthsInYear;
+ y++;
+ monthsInYear = InternalIsLeapYear(y) ? 13 : 12;
+ }
+ m = i;
+ }
+ else
+ {
+ int monthsInYear;
+ while (i <= 0)
+ {
+ monthsInYear = InternalIsLeapYear(y - 1) ? 13 : 12;
+ i += monthsInYear;
+ y--;
+ }
+ m = i;
+ }
+
+ int days = InternalGetDaysInMonth(y, m);
+ if (d > days)
+ {
+ d = days;
+ }
+ DateTime dt = LunarToTime(time, y, m, d);
+
+ CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (dt);
+ }
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ CheckTicksRange(time.Ticks);
+
+ int y = 0; int m = 0; int d = 0;
+ TimeToLunar(time, ref y, ref m, ref d);
+
+ y += years;
+
+ if (m == 13 && !InternalIsLeapYear(y))
+ {
+ m = 12;
+ d = InternalGetDaysInMonth(y, m);
+ }
+ int DaysInMonths = InternalGetDaysInMonth(y, m);
+ if (d > DaysInMonths)
+ {
+ d = DaysInMonths;
+ }
+
+ DateTime dt = LunarToTime(time, y, m, d);
+ CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (dt);
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and [354|355 |383|384].
+ //
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+
+ int y = 0; int m = 0; int d = 0;
+ TimeToLunar(time, ref y, ref m, ref d);
+
+ for (int i = 1; i < m; i++)
+ {
+ d = d + InternalGetDaysInMonth(y, i);
+ }
+ return d;
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 29 or 30.
+ //
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+
+ int y = 0; int m = 0; int d = 0;
+ TimeToLunar(time, ref y, ref m, ref d);
+
+ return d;
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ year = CheckYearRange(year, era);
+
+ int Days = 0;
+ int monthsInYear = InternalIsLeapYear(year) ? 13 : 12;
+
+ while (monthsInYear != 0)
+ Days += InternalGetDaysInMonth(year, monthsInYear--);
+
+ return Days;
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 13.
+ //
+
+ public override int GetMonth(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+
+ int y = 0; int m = 0; int d = 0;
+ TimeToLunar(time, ref y, ref m, ref d);
+
+ return m;
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and MaxCalendarYear.
+ //
+
+ public override int GetYear(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+
+ int y = 0; int m = 0; int d = 0;
+ TimeToLunar(time, ref y, ref m, ref d);
+
+ return GetYear(y, time);
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return ((DayOfWeek)((int)(time.Ticks / Calendar.TicksPerDay + 1) % 7));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ year = CheckYearRange(year, era);
+ return (InternalIsLeapYear(year) ? 13 : 12);
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ year = CheckYearMonthRange(year, month, era);
+ int daysInMonth = InternalGetDaysInMonth(year, month);
+
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month));
+ }
+ int m = GetYearInfo(year, LeapMonth);
+ return ((m != 0) && (month == (m + 1)));
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ year = CheckYearMonthRange(year, month, era);
+ int m = GetYearInfo(year, LeapMonth);
+ return ((m != 0) && (month == (m + 1)));
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this this year is not a leap year.
+ //
+
+ public override int GetLeapMonth(int year, int era)
+ {
+ year = CheckYearRange(year, era);
+ int month = GetYearInfo(year, LeapMonth);
+ if (month > 0)
+ {
+ return (month + 1);
+ }
+ return 0;
+ }
+
+ internal bool InternalIsLeapYear(int year)
+ {
+ return (GetYearInfo(year, LeapMonth) != 0);
+ }
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ year = CheckYearRange(year, era);
+ return InternalIsLeapYear(year);
+ }
+
+ private const int DEFAULT_GREGORIAN_TWO_DIGIT_YEAR_MAX = 2029;
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(BaseCalendarID, GetYear(new DateTime(DEFAULT_GREGORIAN_TWO_DIGIT_YEAR_MAX, 1, 1)));
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "value",
+ SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxCalendarYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ year = base.ToFourDigitYear(year);
+ CheckYearRange(year, CurrentEra);
+ return (year);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/GregorianCalendar.cs b/src/mscorlib/corefx/System/Globalization/GregorianCalendar.cs
new file mode 100644
index 0000000000..d0933a0fc6
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/GregorianCalendar.cs
@@ -0,0 +1,662 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+//
+
+using System;
+using System.Globalization;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+using System.Threading;
+
+namespace System.Globalization
+{
+ // This calendar recognizes two era values:
+ // 0 CurrentEra (AD)
+ // 1 BeforeCurrentEra (BC)
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+
+ public class GregorianCalendar : Calendar
+ {
+ /*
+ A.D. = anno Domini
+ */
+
+ public const int ADEra = 1;
+
+
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+
+ //
+ // This is the max Gregorian year can be represented by DateTime class. The limitation
+ // is derived from DateTime class.
+ //
+ internal const int MaxYear = 9999;
+
+ internal GregorianCalendarTypes m_type;
+
+ internal static readonly int[] DaysToMonth365 =
+ {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+ };
+
+ internal static readonly int[] DaysToMonth366 =
+ {
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
+ };
+
+ private static volatile Calendar s_defaultInstance;
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ if (m_type < GregorianCalendarTypes.Localized ||
+ m_type > GregorianCalendarTypes.TransliteratedFrench)
+ {
+ throw new SerializationException(
+ String.Format(CultureInfo.CurrentCulture, SR.Serialization_MemberOutOfRange, "type", "GregorianCalendar"));
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MinValue);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+ /*=================================GetDefaultInstance==========================
+ **Action: Internal method to provide a default intance of GregorianCalendar. Used by NLS+ implementation
+ ** and other calendars.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+ internal static Calendar GetDefaultInstance()
+ {
+ if (s_defaultInstance == null)
+ {
+ s_defaultInstance = new GregorianCalendar();
+ }
+ return (s_defaultInstance);
+ }
+
+ // Construct an instance of gregorian calendar.
+
+ public GregorianCalendar() :
+ this(GregorianCalendarTypes.Localized)
+ {
+ }
+
+
+ public GregorianCalendar(GregorianCalendarTypes type)
+ {
+ if ((int)type < (int)GregorianCalendarTypes.Localized || (int)type > (int)GregorianCalendarTypes.TransliteratedFrench)
+ {
+ throw new ArgumentOutOfRangeException(
+ "type",
+ SR.Format(SR.ArgumentOutOfRange_Range,
+ GregorianCalendarTypes.Localized, GregorianCalendarTypes.TransliteratedFrench));
+ }
+ Contract.EndContractBlock();
+ this.m_type = type;
+ }
+
+ public virtual GregorianCalendarTypes CalendarType
+ {
+ get
+ {
+ return (m_type);
+ }
+
+ set
+ {
+ VerifyWritable();
+
+ switch (value)
+ {
+ case GregorianCalendarTypes.Localized:
+ case GregorianCalendarTypes.USEnglish:
+ case GregorianCalendarTypes.MiddleEastFrench:
+ case GregorianCalendarTypes.Arabic:
+ case GregorianCalendarTypes.TransliteratedEnglish:
+ case GregorianCalendarTypes.TransliteratedFrench:
+ m_type = value;
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException("m_type", SR.ArgumentOutOfRange_Enum);
+ }
+ }
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ // By returning different ID for different variations of GregorianCalendar,
+ // we can support the Transliterated Gregorian calendar.
+ // DateTimeFormatInfo will use this ID to get formatting information about
+ // the calendar.
+ return ((CalendarId)m_type);
+ }
+ }
+
+
+ // Returns a given date part of this DateTime. This method is used
+ // to compute the year, day-of-year, month, or day part.
+ internal virtual int GetDatePart(long ticks, int part)
+ {
+ // n = number of days since 1/1/0001
+ int n = (int)(ticks / TicksPerDay);
+ // y400 = number of whole 400-year periods since 1/1/0001
+ int y400 = n / DaysPer400Years;
+ // n = day number within 400-year period
+ n -= y400 * DaysPer400Years;
+ // y100 = number of whole 100-year periods within 400-year period
+ int y100 = n / DaysPer100Years;
+ // Last 100-year period has an extra day, so decrement result if 4
+ if (y100 == 4) y100 = 3;
+ // n = day number within 100-year period
+ n -= y100 * DaysPer100Years;
+ // y4 = number of whole 4-year periods within 100-year period
+ int y4 = n / DaysPer4Years;
+ // n = day number within 4-year period
+ n -= y4 * DaysPer4Years;
+ // y1 = number of whole years within 4-year period
+ int y1 = n / DaysPerYear;
+ // Last year has an extra day, so decrement result if 4
+ if (y1 == 4) y1 = 3;
+ // If year was requested, compute and return it
+ if (part == DatePartYear)
+ {
+ return (y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1);
+ }
+ // n = day number within year
+ n -= y1 * DaysPerYear;
+ // If day-of-year was requested, return it
+ if (part == DatePartDayOfYear)
+ {
+ return (n + 1);
+ }
+ // Leap year calculation looks different from IsLeapYear since y1, y4,
+ // and y100 are relative to year 1, not year 0
+ bool leapYear = (y1 == 3 && (y4 != 24 || y100 == 3));
+ int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
+ // All months have less than 32 days, so n >> 5 is a good conservative
+ // estimate for the month
+ int m = n >> 5 + 1;
+ // m = 1-based month number
+ while (n >= days[m]) m++;
+ // If month was requested, return it
+ if (part == DatePartMonth) return (m);
+ // Return 1-based day-of-month
+ return (n - days[m - 1] + 1);
+ }
+
+ /*=================================GetAbsoluteDate==========================
+ **Action: Gets the absolute date for the given Gregorian date. The absolute date means
+ ** the number of days from January 1st, 1 A.D.
+ **Returns: the absolute date
+ **Arguments:
+ ** year the Gregorian year
+ ** month the Gregorian month
+ ** day the day
+ **Exceptions:
+ ** ArgumentOutOfRangException if year, month, day value is valid.
+ **Note:
+ ** This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars.
+ ** Number of Days in Prior Years (both common and leap years) +
+ ** Number of Days in Prior Months of Current Year +
+ ** Number of Days in Current Month
+ **
+ ============================================================================*/
+
+ internal static long GetAbsoluteDate(int year, int month, int day)
+ {
+ if (year >= 1 && year <= MaxYear && month >= 1 && month <= 12)
+ {
+ int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) ? DaysToMonth366 : DaysToMonth365;
+ if (day >= 1 && (day <= days[month] - days[month - 1]))
+ {
+ int y = year - 1;
+ int absoluteDate = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
+ return (absoluteDate);
+ }
+ }
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+
+ // Returns the tick count corresponding to the given year, month, and day.
+ // Will check the if the parameters are valid.
+ internal virtual long DateToTicks(int year, int month, int day)
+ {
+ return (GetAbsoluteDate(year, month, day) * TicksPerDay);
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ -120000,
+ 120000));
+ }
+ Contract.EndContractBlock();
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+ int i = m - 1 + months;
+ if (i >= 0)
+ {
+ m = i % 12 + 1;
+ y = y + i / 12;
+ }
+ else
+ {
+ m = 12 + (i + 1) % 12;
+ y = y + (i - 11) / 12;
+ }
+ int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365;
+ int days = (daysArray[m] - daysArray[m - 1]);
+
+ if (d > days)
+ {
+ d = days;
+ }
+ long ticks = DateToTicks(y, m, d) + time.Ticks % TicksPerDay;
+ Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+
+ return (new DateTime(ticks));
+ }
+
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (AddMonths(time, years * 12));
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDay));
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDayOfYear));
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ if (era == CurrentEra || era == ADEra)
+ {
+ if (year < 1 || year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException("year", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, MaxYear));
+ }
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365);
+ return (days[month] - days[month - 1]);
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ if (era == CurrentEra || era == ADEra)
+ {
+ if (year >= 1 && year <= MaxYear)
+ {
+ return ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365);
+ }
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxYear));
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ // Returns the era for the specified DateTime value.
+
+ public override int GetEra(DateTime time)
+ {
+ return (ADEra);
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { ADEra });
+ }
+ }
+
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+ public override int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartMonth));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ if (era == CurrentEra || era == ADEra)
+ {
+ if (year >= 1 && year <= MaxYear)
+ {
+ return (12);
+ }
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxYear));
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and 9999.
+ //
+
+ public override int GetYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartYear));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, 12));
+ }
+ Contract.EndContractBlock();
+
+ if (era != CurrentEra && era != ADEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ if (year < 1 || year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear));
+ }
+
+ if (day < 1 || day > GetDaysInMonth(year, month))
+ {
+ throw new ArgumentOutOfRangeException("day", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, GetDaysInMonth(year, month)));
+ }
+ if (!IsLeapYear(year))
+ {
+ return (false);
+ }
+ if (month == 2 && day == 29)
+ {
+ return (true);
+ }
+ return (false);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ if (era != CurrentEra && era != ADEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ if (year < 1 || year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, 1, MaxYear));
+ }
+ Contract.EndContractBlock();
+ return (0);
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ if (era != CurrentEra && era != ADEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ if (year < 1 || year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, 1, MaxYear));
+ }
+
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, 12));
+ }
+ Contract.EndContractBlock();
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ if (era == CurrentEra || era == ADEra)
+ {
+ if (year >= 1 && year <= MaxYear)
+ {
+ return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
+ }
+
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, 1, MaxYear));
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ if (era == CurrentEra || era == ADEra)
+ {
+ return new DateTime(year, month, day, hour, minute, second, millisecond);
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal override Boolean TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result)
+ {
+ if (era == CurrentEra || era == ADEra)
+ {
+ try
+ {
+ result = new DateTime(year, month, day, hour, minute, second, millisecond);
+ return true;
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ result = DateTime.Now;
+ return false;
+ }
+ catch (ArgumentException)
+ {
+ result = DateTime.Now;
+ return false;
+ }
+ }
+ result = DateTime.MinValue;
+ return false;
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 2029;
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ MaxYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, 1, MaxYear));
+ }
+ return (base.ToFourDigitYear(year));
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/GregorianCalendarHelper.cs b/src/mscorlib/corefx/System/Globalization/GregorianCalendarHelper.cs
new file mode 100644
index 0000000000..f595e72d0d
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/GregorianCalendarHelper.cs
@@ -0,0 +1,668 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+using System.Threading;
+
+namespace System.Globalization
+{
+ // Gregorian Calendars use Era Info
+ [Serializable]
+ internal class EraInfo
+ {
+ internal int era; // The value of the era.
+ internal long ticks; // The time in ticks when the era starts
+ internal int yearOffset; // The offset to Gregorian year when the era starts.
+ // Gregorian Year = Era Year + yearOffset
+ // Era Year = Gregorian Year - yearOffset
+ internal int minEraYear; // Min year value in this era. Generally, this value is 1, but this may
+ // be affected by the DateTime.MinValue;
+ internal int maxEraYear; // Max year value in this era. (== the year length of the era + 1)
+
+ [OptionalField(VersionAdded = 4)]
+ internal String eraName; // The era name
+ [OptionalField(VersionAdded = 4)]
+ internal String abbrevEraName; // Abbreviated Era Name
+ [OptionalField(VersionAdded = 4)]
+ internal String englishEraName; // English era name
+
+ internal EraInfo(int era, int startYear, int startMonth, int startDay, int yearOffset, int minEraYear, int maxEraYear)
+ {
+ this.era = era;
+ this.yearOffset = yearOffset;
+ this.minEraYear = minEraYear;
+ this.maxEraYear = maxEraYear;
+ this.ticks = new DateTime(startYear, startMonth, startDay).Ticks;
+ }
+
+ internal EraInfo(int era, int startYear, int startMonth, int startDay, int yearOffset, int minEraYear, int maxEraYear,
+ String eraName, String abbrevEraName, String englishEraName)
+ {
+ this.era = era;
+ this.yearOffset = yearOffset;
+ this.minEraYear = minEraYear;
+ this.maxEraYear = maxEraYear;
+ this.ticks = new DateTime(startYear, startMonth, startDay).Ticks;
+ this.eraName = eraName;
+ this.abbrevEraName = abbrevEraName;
+ this.englishEraName = englishEraName;
+ }
+ }
+
+ // This calendar recognizes two era values:
+ // 0 CurrentEra (AD)
+ // 1 BeforeCurrentEra (BC)
+ [Serializable]
+ internal class GregorianCalendarHelper
+ {
+ // 1 tick = 100ns = 10E-7 second
+ // Number of ticks per time unit
+ internal const long TicksPerMillisecond = 10000;
+ internal const long TicksPerSecond = TicksPerMillisecond * 1000;
+ internal const long TicksPerMinute = TicksPerSecond * 60;
+ internal const long TicksPerHour = TicksPerMinute * 60;
+ internal const long TicksPerDay = TicksPerHour * 24;
+
+ // Number of milliseconds per time unit
+ internal const int MillisPerSecond = 1000;
+ internal const int MillisPerMinute = MillisPerSecond * 60;
+ internal const int MillisPerHour = MillisPerMinute * 60;
+ internal const int MillisPerDay = MillisPerHour * 24;
+
+ // Number of days in a non-leap year
+ internal const int DaysPerYear = 365;
+ // Number of days in 4 years
+ internal const int DaysPer4Years = DaysPerYear * 4 + 1;
+ // Number of days in 100 years
+ internal const int DaysPer100Years = DaysPer4Years * 25 - 1;
+ // Number of days in 400 years
+ internal const int DaysPer400Years = DaysPer100Years * 4 + 1;
+
+ // Number of days from 1/1/0001 to 1/1/10000
+ internal const int DaysTo10000 = DaysPer400Years * 25 - 366;
+
+ internal const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
+
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+
+ //
+ // This is the max Gregorian year can be represented by DateTime class. The limitation
+ // is derived from DateTime class.
+ //
+ internal int MaxYear
+ {
+ get
+ {
+ return (m_maxYear);
+ }
+ }
+
+ internal static readonly int[] DaysToMonth365 =
+ {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+ };
+
+ internal static readonly int[] DaysToMonth366 =
+ {
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
+ };
+
+ [OptionalField(VersionAdded = 1)]
+ internal int m_maxYear = 9999;
+ [OptionalField(VersionAdded = 1)]
+ internal int m_minYear;
+ internal Calendar m_Cal;
+
+ [OptionalField(VersionAdded = 1)]
+ internal EraInfo[] m_EraInfo;
+ [OptionalField(VersionAdded = 1)]
+ internal int[] m_eras = null;
+
+
+ // Construct an instance of gregorian calendar.
+ internal GregorianCalendarHelper(Calendar cal, EraInfo[] eraInfo)
+ {
+ m_Cal = cal;
+ m_EraInfo = eraInfo;
+ m_maxYear = m_EraInfo[0].maxEraYear;
+ m_minYear = m_EraInfo[0].minEraYear; ;
+ }
+
+ /*=================================GetGregorianYear==========================
+ **Action: Get the Gregorian year value for the specified year in an era.
+ **Returns: The Gregorian year value.
+ **Arguments:
+ ** year the year value in Japanese calendar
+ ** era the Japanese emperor era value.
+ **Exceptions:
+ ** ArgumentOutOfRangeException if year value is invalid or era value is invalid.
+ ============================================================================*/
+
+ internal int GetGregorianYear(int year, int era)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (era == Calendar.CurrentEra)
+ {
+ era = m_Cal.CurrentEraValue;
+ }
+
+ for (int i = 0; i < m_EraInfo.Length; i++)
+ {
+ if (era == m_EraInfo[i].era)
+ {
+ if (year < m_EraInfo[i].minEraYear || year > m_EraInfo[i].maxEraYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ m_EraInfo[i].minEraYear,
+ m_EraInfo[i].maxEraYear));
+ }
+ return (m_EraInfo[i].yearOffset + year);
+ }
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal bool IsValidYear(int year, int era)
+ {
+ if (year < 0)
+ {
+ return false;
+ }
+
+ if (era == Calendar.CurrentEra)
+ {
+ era = m_Cal.CurrentEraValue;
+ }
+
+ for (int i = 0; i < m_EraInfo.Length; i++)
+ {
+ if (era == m_EraInfo[i].era)
+ {
+ if (year < m_EraInfo[i].minEraYear || year > m_EraInfo[i].maxEraYear)
+ {
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ // Returns a given date part of this DateTime. This method is used
+ // to compute the year, day-of-year, month, or day part.
+ internal virtual int GetDatePart(long ticks, int part)
+ {
+ CheckTicksRange(ticks);
+ // n = number of days since 1/1/0001
+ int n = (int)(ticks / TicksPerDay);
+ // y400 = number of whole 400-year periods since 1/1/0001
+ int y400 = n / DaysPer400Years;
+ // n = day number within 400-year period
+ n -= y400 * DaysPer400Years;
+ // y100 = number of whole 100-year periods within 400-year period
+ int y100 = n / DaysPer100Years;
+ // Last 100-year period has an extra day, so decrement result if 4
+ if (y100 == 4) y100 = 3;
+ // n = day number within 100-year period
+ n -= y100 * DaysPer100Years;
+ // y4 = number of whole 4-year periods within 100-year period
+ int y4 = n / DaysPer4Years;
+ // n = day number within 4-year period
+ n -= y4 * DaysPer4Years;
+ // y1 = number of whole years within 4-year period
+ int y1 = n / DaysPerYear;
+ // Last year has an extra day, so decrement result if 4
+ if (y1 == 4) y1 = 3;
+ // If year was requested, compute and return it
+ if (part == DatePartYear)
+ {
+ return (y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1);
+ }
+ // n = day number within year
+ n -= y1 * DaysPerYear;
+ // If day-of-year was requested, return it
+ if (part == DatePartDayOfYear)
+ {
+ return (n + 1);
+ }
+ // Leap year calculation looks different from IsLeapYear since y1, y4,
+ // and y100 are relative to year 1, not year 0
+ bool leapYear = (y1 == 3 && (y4 != 24 || y100 == 3));
+ int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
+ // All months have less than 32 days, so n >> 5 is a good conservative
+ // estimate for the month
+ int m = n >> 5 + 1;
+ // m = 1-based month number
+ while (n >= days[m]) m++;
+ // If month was requested, return it
+ if (part == DatePartMonth) return (m);
+ // Return 1-based day-of-month
+ return (n - days[m - 1] + 1);
+ }
+
+ /*=================================GetAbsoluteDate==========================
+ **Action: Gets the absolute date for the given Gregorian date. The absolute date means
+ ** the number of days from January 1st, 1 A.D.
+ **Returns: the absolute date
+ **Arguments:
+ ** year the Gregorian year
+ ** month the Gregorian month
+ ** day the day
+ **Exceptions:
+ ** ArgumentOutOfRangException if year, month, day value is valid.
+ **Note:
+ ** This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars.
+ ** Number of Days in Prior Years (both common and leap years) +
+ ** Number of Days in Prior Months of Current Year +
+ ** Number of Days in Current Month
+ **
+ ============================================================================*/
+
+ internal static long GetAbsoluteDate(int year, int month, int day)
+ {
+ if (year >= 1 && year <= 9999 && month >= 1 && month <= 12)
+ {
+ int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) ? DaysToMonth366 : DaysToMonth365;
+ if (day >= 1 && (day <= days[month] - days[month - 1]))
+ {
+ int y = year - 1;
+ int absoluteDate = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
+ return (absoluteDate);
+ }
+ }
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+
+ // Returns the tick count corresponding to the given year, month, and day.
+ // Will check the if the parameters are valid.
+ internal static long DateToTicks(int year, int month, int day)
+ {
+ return (GetAbsoluteDate(year, month, day) * TicksPerDay);
+ }
+
+ // Return the tick count corresponding to the given hour, minute, second.
+ // Will check the if the parameters are valid.
+ internal static long TimeToTicks(int hour, int minute, int second, int millisecond)
+ {
+ //TimeSpan.TimeToTicks is a family access function which does no error checking, so
+ //we need to put some error checking out here.
+ if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60)
+ {
+ if (millisecond < 0 || millisecond >= MillisPerSecond)
+ {
+ throw new ArgumentOutOfRangeException(
+ "millisecond",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ MillisPerSecond - 1));
+ }
+ return (InternalGloablizationHelper.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond); ;
+ }
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+ }
+
+
+ internal void CheckTicksRange(long ticks)
+ {
+ if (ticks < m_Cal.MinSupportedDateTime.Ticks || ticks > m_Cal.MaxSupportedDateTime.Ticks)
+ {
+ throw new ArgumentOutOfRangeException(
+ "time",
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.ArgumentOutOfRange_CalendarRange,
+ m_Cal.MinSupportedDateTime,
+ m_Cal.MaxSupportedDateTime));
+ }
+ Contract.EndContractBlock();
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+ public DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ -120000,
+ 120000));
+ }
+ Contract.EndContractBlock();
+ CheckTicksRange(time.Ticks);
+
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+ int i = m - 1 + months;
+ if (i >= 0)
+ {
+ m = i % 12 + 1;
+ y = y + i / 12;
+ }
+ else
+ {
+ m = 12 + (i + 1) % 12;
+ y = y + (i - 11) / 12;
+ }
+ int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365;
+ int days = (daysArray[m] - daysArray[m - 1]);
+
+ if (d > days)
+ {
+ d = days;
+ }
+ long ticks = DateToTicks(y, m, d) + (time.Ticks % TicksPerDay);
+ Calendar.CheckAddResult(ticks, m_Cal.MinSupportedDateTime, m_Cal.MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+ public DateTime AddYears(DateTime time, int years)
+ {
+ return (AddMonths(time, years * 12));
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+ public int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDay));
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+ public DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return ((DayOfWeek)((time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+ public int GetDayOfYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDayOfYear));
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+ [Pure]
+ public int GetDaysInMonth(int year, int month, int era)
+ {
+ //
+ // Convert year/era value to Gregorain year value.
+ //
+ year = GetGregorianYear(year, era);
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365);
+ return (days[month] - days[month - 1]);
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public int GetDaysInYear(int year, int era)
+ {
+ //
+ // Convert year/era value to Gregorain year value.
+ //
+ year = GetGregorianYear(year, era);
+ return ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365);
+ }
+
+ // Returns the era for the specified DateTime value.
+ public int GetEra(DateTime time)
+ {
+ long ticks = time.Ticks;
+ // The assumption here is that m_EraInfo is listed in reverse order.
+ for (int i = 0; i < m_EraInfo.Length; i++)
+ {
+ if (ticks >= m_EraInfo[i].ticks)
+ {
+ return (m_EraInfo[i].era);
+ }
+ }
+ throw new ArgumentOutOfRangeException("time", SR.ArgumentOutOfRange_Era);
+ }
+
+
+ public int[] Eras
+ {
+ get
+ {
+ if (m_eras == null)
+ {
+ m_eras = new int[m_EraInfo.Length];
+ for (int i = 0; i < m_EraInfo.Length; i++)
+ {
+ m_eras[i] = m_EraInfo[i].era;
+ }
+ }
+ return ((int[])m_eras.Clone());
+ }
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+ public int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartMonth));
+ }
+
+ // Returns the number of months in the specified year and era.
+ public int GetMonthsInYear(int year, int era)
+ {
+ year = GetGregorianYear(year, era);
+ return (12);
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and 9999.
+ //
+ public int GetYear(DateTime time)
+ {
+ long ticks = time.Ticks;
+ int year = GetDatePart(ticks, DatePartYear);
+ for (int i = 0; i < m_EraInfo.Length; i++)
+ {
+ if (ticks >= m_EraInfo[i].ticks)
+ {
+ return (year - m_EraInfo[i].yearOffset);
+ }
+ }
+ throw new ArgumentException(SR.Argument_NoEra);
+ }
+
+ // Returns the year that match the specified Gregorian year. The returned value is an
+ // integer between 1 and 9999.
+ //
+ public int GetYear(int year, DateTime time)
+ {
+ long ticks = time.Ticks;
+ for (int i = 0; i < m_EraInfo.Length; i++)
+ {
+ // while calculating dates with JapaneseLuniSolarCalendar, we can run into cases right after the start of the era
+ // and still belong to the month which is started in previous era. Calculating equivalent calendar date will cause
+ // using the new era info which will have the year offset equal to the year we are calculating year = m_EraInfo[i].yearOffset
+ // which will end up with zero as calendar year.
+ // We should use the previous era info instead to get the right year number. Example of such date is Feb 2nd 1989
+ if (ticks >= m_EraInfo[i].ticks && year > m_EraInfo[i].yearOffset)
+ {
+ return (year - m_EraInfo[i].yearOffset);
+ }
+ }
+ throw new ArgumentException(SR.Argument_NoEra);
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+ public bool IsLeapDay(int year, int month, int day, int era)
+ {
+ // year/month/era checking is done in GetDaysInMonth()
+ if (day < 1 || day > GetDaysInMonth(year, month, era))
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ GetDaysInMonth(year, month, era)));
+ }
+ Contract.EndContractBlock();
+
+ if (!IsLeapYear(year, era))
+ {
+ return (false);
+ }
+
+ if (month == 2 && day == 29)
+ {
+ return (true);
+ }
+
+ return (false);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+ public int GetLeapMonth(int year, int era)
+ {
+ year = GetGregorianYear(year, era);
+ return (0);
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+ public bool IsLeapMonth(int year, int month, int era)
+ {
+ year = GetGregorianYear(year, era);
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ 12));
+ }
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+ public bool IsLeapYear(int year, int era)
+ {
+ year = GetGregorianYear(year, era);
+ return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+ public DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ year = GetGregorianYear(year, era);
+ long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second, millisecond);
+ CheckTicksRange(ticks);
+ return (new DateTime(ticks));
+ }
+
+ public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ CheckTicksRange(time.Ticks);
+ // Use GregorianCalendar to get around the problem that the implmentation in Calendar.GetWeekOfYear()
+ // can call GetYear() that exceeds the supported range of the Gregorian-based calendars.
+ return (GregorianCalendar.GetDefaultInstance().GetWeekOfYear(time, rule, firstDayOfWeek));
+ }
+
+
+ public int ToFourDigitYear(int year, int twoDigitYearMax)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year < 100)
+ {
+ int y = year % 100;
+ return ((twoDigitYearMax / 100 - (y > twoDigitYearMax % 100 ? 1 : 0)) * 100 + y);
+ }
+
+ if (year < m_minYear || year > m_maxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, m_minYear, m_maxYear));
+ }
+ // If the year value is above 100, just return the year value. Don't have to do
+ // the TwoDigitYearMax comparison.
+ return (year);
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/GregorianCalendarTypes.cs b/src/mscorlib/corefx/System/Globalization/GregorianCalendarTypes.cs
new file mode 100644
index 0000000000..a14010fe60
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/GregorianCalendarTypes.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ // Note: The values of the members of this enum must match the coresponding values
+ // in the CalendarId enum (since we cast between GregorianCalendarTypes and CalendarId).
+ [Serializable]
+ public enum GregorianCalendarTypes
+ {
+ Localized = CalendarId.GREGORIAN,
+ USEnglish = CalendarId.GREGORIAN_US,
+ MiddleEastFrench = CalendarId.GREGORIAN_ME_FRENCH,
+ Arabic = CalendarId.GREGORIAN_ARABIC,
+ TransliteratedEnglish = CalendarId.GREGORIAN_XLIT_ENGLISH,
+ TransliteratedFrench = CalendarId.GREGORIAN_XLIT_FRENCH,
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/HebrewCalendar.cs b/src/mscorlib/corefx/System/Globalization/HebrewCalendar.cs
new file mode 100644
index 0000000000..5fbf2e0f09
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/HebrewCalendar.cs
@@ -0,0 +1,1123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Rules for the Hebrew calendar:
+ // - The Hebrew calendar is both a Lunar (months) and Solar (years)
+ // calendar, but allows for a week of seven days.
+ // - Days begin at sunset.
+ // - Leap Years occur in the 3, 6, 8, 11, 14, 17, & 19th years of a
+ // 19-year cycle. Year = leap iff ((7y+1) mod 19 < 7).
+ // - There are 12 months in a common year and 13 months in a leap year.
+ // - In a common year, the 6th month, Adar, has 29 days. In a leap
+ // year, the 6th month, Adar I, has 30 days and the leap month,
+ // Adar II, has 29 days.
+ // - Common years have 353-355 days. Leap years have 383-385 days.
+ // - The Hebrew new year (Rosh HaShanah) begins on the 1st of Tishri,
+ // the 7th month in the list below.
+ // - The new year may not begin on Sunday, Wednesday, or Friday.
+ // - If the new year would fall on a Tuesday and the conjunction of
+ // the following year were at midday or later, the new year is
+ // delayed until Thursday.
+ // - If the new year would fall on a Monday after a leap year, the
+ // new year is delayed until Tuesday.
+ // - The length of the 8th and 9th months vary from year to year,
+ // depending on the overall length of the year.
+ // - The length of a year is determined by the dates of the new
+ // years (Tishri 1) preceding and following the year in question.
+ // - The 2th month is long (30 days) if the year has 355 or 385 days.
+ // - The 3th month is short (29 days) if the year has 353 or 383 days.
+ // - The Hebrew months are:
+ // 1. Tishri (30 days)
+ // 2. Heshvan (29 or 30 days)
+ // 3. Kislev (29 or 30 days)
+ // 4. Teveth (29 days)
+ // 5. Shevat (30 days)
+ // 6. Adar I (30 days)
+ // 7. Adar {II} (29 days, this only exists if that year is a leap year)
+ // 8. Nisan (30 days)
+ // 9. Iyyar (29 days)
+ // 10. Sivan (30 days)
+ // 11. Tammuz (29 days)
+ // 12. Av (30 days)
+ // 13. Elul (29 days)
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1583/01/01 2239/09/29
+ ** Hebrew 5343/04/07 5999/13/29
+ */
+
+ // Includes CHebrew implemetation;i.e All the code necessary for converting
+ // Gregorian to Hebrew Lunar from 1583 to 2239.
+
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class HebrewCalendar : Calendar
+ {
+ public static readonly int HebrewEra = 1;
+
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+ internal const int DatePartDayOfWeek = 4;
+
+ //
+ // Hebrew Translation Table.
+ //
+ // This table is used to get the following Hebrew calendar information for a
+ // given Gregorian year:
+ // 1. The day of the Hebrew month corresponding to Gregorian January 1st
+ // for a given Gregorian year.
+ // 2. The month of the Hebrew month corresponding to Gregorian January 1st
+ // for a given Gregorian year.
+ // The information is not directly in the table. Instead, the info is decoded
+ // by special values (numbers above 29 and below 1).
+ // 3. The type of the Hebrew year for a given Gregorian year.
+ //
+
+ /*
+ More notes:
+
+ This table includes 2 numbers for each year.
+ The offset into the table determines the year. (offset 0 is Gregorian year 1500)
+ 1st number determines the day of the Hebrew month coresponeds to January 1st.
+ 2nd number determines the type of the Hebrew year. (the type determines how
+ many days are there in the year.)
+
+ normal years : 1 = 353 days 2 = 354 days 3 = 355 days.
+ Leap years : 4 = 383 5 384 6 = 385 days.
+
+ A 99 means the year is not supported for translation.
+ for convenience the table was defined for 750 year,
+ but only 640 years are supported. (from 1583 to 2239)
+ the years before 1582 (starting of Georgian calander)
+ and after 2239, are filled with 99.
+
+ Greogrian January 1st falls usually in Tevet (4th month). Tevet has always 29 days.
+ That's why, there no nead to specify the lunar month in the table.
+ There are exceptions, these are coded by giving numbers above 29 and below 1.
+ Actual decoding is takenig place whenever fetching information from the table.
+ The function for decoding is in GetLunarMonthDay().
+
+ Example:
+ The data for 2000 - 2005 A.D. is:
+
+ 23,6,6,1,17,2,27,6,7,3, // 2000 - 2004
+
+ For year 2000, we know it has a Hebrew year type 6, which means it has 385 days.
+ And 1/1/2000 A.D. is Hebrew year 5760, 23rd day of 4th month.
+ */
+
+ //
+ // Jewish Era in use today is dated from the supposed year of the
+ // Creation with its beginning in 3761 B.C.
+ //
+
+ // The Hebrew year of Gregorian 1st year AD.
+ // 0001/01/01 AD is Hebrew 3760/01/01
+ private const int HebrewYearOf1AD = 3760;
+
+ // The first Gregorian year in HebrewTable.
+ private const int FirstGregorianTableYear = 1583; // == Hebrew Year 5343
+ // The last Gregorian year in HebrewTable.
+ private const int LastGregorianTableYear = 2239; // == Hebrew Year 5999
+ private const int TABLESIZE = (LastGregorianTableYear - FirstGregorianTableYear);
+
+ private const int MinHebrewYear = HebrewYearOf1AD + FirstGregorianTableYear; // == 5343
+ private const int MaxHebrewYear = HebrewYearOf1AD + LastGregorianTableYear; // == 5999
+
+ private static readonly byte[] s_hebrewTable = {
+ 7,3,17,3, // 1583-1584 (Hebrew year: 5343 - 5344)
+ 0,4,11,2,21,6,1,3,13,2, // 1585-1589
+ 25,4,5,3,16,2,27,6,9,1, // 1590-1594
+ 20,2,0,6,11,3,23,4,4,2, // 1595-1599
+ 14,3,27,4,8,2,18,3,28,6, // 1600
+ 11,1,22,5,2,3,12,3,25,4, // 1605
+ 6,2,16,3,26,6,8,2,20,1, // 1610
+ 0,6,11,2,24,4,4,3,15,2, // 1615
+ 25,6,8,1,19,2,29,6,9,3, // 1620
+ 22,4,3,2,13,3,25,4,6,3, // 1625
+ 17,2,27,6,7,3,19,2,31,4, // 1630
+ 11,3,23,4,5,2,15,3,25,6, // 1635
+ 6,2,19,1,29,6,10,2,22,4, // 1640
+ 3,3,14,2,24,6,6,1,17,3, // 1645
+ 28,5,8,3,20,1,32,5,12,3, // 1650
+ 22,6,4,1,16,2,26,6,6,3, // 1655
+ 17,2,0,4,10,3,22,4,3,2, // 1660
+ 14,3,24,6,5,2,17,1,28,6, // 1665
+ 9,2,19,3,31,4,13,2,23,6, // 1670
+ 3,3,15,1,27,5,7,3,17,3, // 1675
+ 29,4,11,2,21,6,3,1,14,2, // 1680
+ 25,6,5,3,16,2,28,4,9,3, // 1685
+ 20,2,0,6,12,1,23,6,4,2, // 1690
+ 14,3,26,4,8,2,18,3,0,4, // 1695
+ 10,3,21,5,1,3,13,1,24,5, // 1700
+ 5,3,15,3,27,4,8,2,19,3, // 1705
+ 29,6,10,2,22,4,3,3,14,2, // 1710
+ 26,4,6,3,18,2,28,6,10,1, // 1715
+ 20,6,2,2,12,3,24,4,5,2, // 1720
+ 16,3,28,4,8,3,19,2,0,6, // 1725
+ 12,1,23,5,3,3,14,3,26,4, // 1730
+ 7,2,17,3,28,6,9,2,21,4, // 1735
+ 1,3,13,2,25,4,5,3,16,2, // 1740
+ 27,6,9,1,19,3,0,5,11,3, // 1745
+ 23,4,4,2,14,3,25,6,7,1, // 1750
+ 18,2,28,6,9,3,21,4,2,2, // 1755
+ 12,3,25,4,6,2,16,3,26,6, // 1760
+ 8,2,20,1,0,6,11,2,22,6, // 1765
+ 4,1,15,2,25,6,6,3,18,1, // 1770
+ 29,5,9,3,22,4,2,3,13,2, // 1775
+ 23,6,4,3,15,2,27,4,7,3, // 1780
+ 19,2,31,4,11,3,21,6,3,2, // 1785
+ 15,1,25,6,6,2,17,3,29,4, // 1790
+ 10,2,20,6,3,1,13,3,24,5, // 1795
+ 4,3,16,1,27,5,7,3,17,3, // 1800
+ 0,4,11,2,21,6,1,3,13,2, // 1805
+ 25,4,5,3,16,2,29,4,9,3, // 1810
+ 19,6,30,2,13,1,23,6,4,2, // 1815
+ 14,3,27,4,8,2,18,3,0,4, // 1820
+ 11,3,22,5,2,3,14,1,26,5, // 1825
+ 6,3,16,3,28,4,10,2,20,6, // 1830
+ 30,3,11,2,24,4,4,3,15,2, // 1835
+ 25,6,8,1,19,2,29,6,9,3, // 1840
+ 22,4,3,2,13,3,25,4,7,2, // 1845
+ 17,3,27,6,9,1,21,5,1,3, // 1850
+ 11,3,23,4,5,2,15,3,25,6, // 1855
+ 6,2,19,1,29,6,10,2,22,4, // 1860
+ 3,3,14,2,24,6,6,1,18,2, // 1865
+ 28,6,8,3,20,4,2,2,12,3, // 1870
+ 24,4,4,3,16,2,26,6,6,3, // 1875
+ 17,2,0,4,10,3,22,4,3,2, // 1880
+ 14,3,24,6,5,2,17,1,28,6, // 1885
+ 9,2,21,4,1,3,13,2,23,6, // 1890
+ 5,1,15,3,27,5,7,3,19,1, // 1895
+ 0,5,10,3,22,4,2,3,13,2, // 1900
+ 24,6,4,3,15,2,27,4,8,3, // 1905
+ 20,4,1,2,11,3,22,6,3,2, // 1910
+ 15,1,25,6,7,2,17,3,29,4, // 1915
+ 10,2,21,6,1,3,13,1,24,5, // 1920
+ 5,3,15,3,27,4,8,2,19,6, // 1925
+ 1,1,12,2,22,6,3,3,14,2, // 1930
+ 26,4,6,3,18,2,28,6,10,1, // 1935
+ 20,6,2,2,12,3,24,4,5,2, // 1940
+ 16,3,28,4,9,2,19,6,30,3, // 1945
+ 12,1,23,5,3,3,14,3,26,4, // 1950
+ 7,2,17,3,28,6,9,2,21,4, // 1955
+ 1,3,13,2,25,4,5,3,16,2, // 1960
+ 27,6,9,1,19,6,30,2,11,3, // 1965
+ 23,4,4,2,14,3,27,4,7,3, // 1970
+ 18,2,28,6,11,1,22,5,2,3, // 1975
+ 12,3,25,4,6,2,16,3,26,6, // 1980
+ 8,2,20,4,30,3,11,2,24,4, // 1985
+ 4,3,15,2,25,6,8,1,18,3, // 1990
+ 29,5,9,3,22,4,3,2,13,3, // 1995
+ 23,6,6,1,17,2,27,6,7,3, // 2000 - 2004
+ 20,4,1,2,11,3,23,4,5,2, // 2005 - 2009
+ 15,3,25,6,6,2,19,1,29,6, // 2010
+ 10,2,20,6,3,1,14,2,24,6, // 2015
+ 4,3,17,1,28,5,8,3,20,4, // 2020
+ 1,3,12,2,22,6,2,3,14,2, // 2025
+ 26,4,6,3,17,2,0,4,10,3, // 2030
+ 20,6,1,2,14,1,24,6,5,2, // 2035
+ 15,3,28,4,9,2,19,6,1,1, // 2040
+ 12,3,23,5,3,3,15,1,27,5, // 2045
+ 7,3,17,3,29,4,11,2,21,6, // 2050
+ 1,3,12,2,25,4,5,3,16,2, // 2055
+ 28,4,9,3,19,6,30,2,12,1, // 2060
+ 23,6,4,2,14,3,26,4,8,2, // 2065
+ 18,3,0,4,10,3,22,5,2,3, // 2070
+ 14,1,25,5,6,3,16,3,28,4, // 2075
+ 9,2,20,6,30,3,11,2,23,4, // 2080
+ 4,3,15,2,27,4,7,3,19,2, // 2085
+ 29,6,11,1,21,6,3,2,13,3, // 2090
+ 25,4,6,2,17,3,27,6,9,1, // 2095
+ 20,5,30,3,10,3,22,4,3,2, // 2100
+ 14,3,24,6,5,2,17,1,28,6, // 2105
+ 9,2,21,4,1,3,13,2,23,6, // 2110
+ 5,1,16,2,27,6,7,3,19,4, // 2115
+ 30,2,11,3,23,4,3,3,14,2, // 2120
+ 25,6,5,3,16,2,28,4,9,3, // 2125
+ 21,4,2,2,12,3,23,6,4,2, // 2130
+ 16,1,26,6,8,2,20,4,30,3, // 2135
+ 11,2,22,6,4,1,14,3,25,5, // 2140
+ 6,3,18,1,29,5,9,3,22,4, // 2145
+ 2,3,13,2,23,6,4,3,15,2, // 2150
+ 27,4,7,3,20,4,1,2,11,3, // 2155
+ 21,6,3,2,15,1,25,6,6,2, // 2160
+ 17,3,29,4,10,2,20,6,3,1, // 2165
+ 13,3,24,5,4,3,17,1,28,5, // 2170
+ 8,3,18,6,1,1,12,2,22,6, // 2175
+ 2,3,14,2,26,4,6,3,17,2, // 2180
+ 28,6,10,1,20,6,1,2,12,3, // 2185
+ 24,4,5,2,15,3,28,4,9,2, // 2190
+ 19,6,33,3,12,1,23,5,3,3, // 2195
+ 13,3,25,4,6,2,16,3,26,6, // 2200
+ 8,2,20,4,30,3,11,2,24,4, // 2205
+ 4,3,15,2,25,6,8,1,18,6, // 2210
+ 33,2,9,3,22,4,3,2,13,3, // 2215
+ 25,4,6,3,17,2,27,6,9,1, // 2220
+ 21,5,1,3,11,3,23,4,5,2, // 2225
+ 15,3,25,6,6,2,19,4,33,3, // 2230
+ 10,2,22,4,3,3,14,2,24,6, // 2235
+ 6,1 // 2240 (Hebrew year: 6000)
+ };
+
+ private const int MaxMonthPlusOne = 14;
+
+ //
+ // The lunar calendar has 6 different variations of month lengths
+ // within a year.
+ //
+ private static readonly byte[] s_lunarMonthLen = {
+ 0,00,00,00,00,00,00,00,00,00,00,00,00,0,
+ 0,30,29,29,29,30,29,30,29,30,29,30,29,0, // 3 common year variations
+ 0,30,29,30,29,30,29,30,29,30,29,30,29,0,
+ 0,30,30,30,29,30,29,30,29,30,29,30,29,0,
+ 0,30,29,29,29,30,30,29,30,29,30,29,30,29, // 3 leap year variations
+ 0,30,29,30,29,30,30,29,30,29,30,29,30,29,
+ 0,30,30,30,29,30,30,29,30,29,30,29,30,29
+ };
+
+ internal static readonly DateTime calendarMinValue = new DateTime(1583, 1, 1);
+ // Gregorian 2239/9/29 = Hebrew 5999/13/29 (last day in Hebrew year 5999).
+ // We can only format/parse Hebrew numbers up to 999, so we limit the max range to Hebrew year 5999.
+ internal static readonly DateTime calendarMaxValue = new DateTime((new DateTime(2239, 9, 29, 23, 59, 59, 999)).Ticks + 9999);
+
+
+
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (calendarMinValue);
+ }
+ }
+
+
+
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (calendarMaxValue);
+ }
+ }
+
+ public HebrewCalendar()
+ {
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.HEBREW);
+ }
+ }
+
+
+ /*=================================CheckHebrewYearValue==========================
+ **Action: Check if the Hebrew year value is supported in this class.
+ **Returns: None.
+ **Arguments: y Hebrew year value
+ ** ear Hebrew era value
+ **Exceptions: ArgumentOutOfRange_Range if the year value is not supported.
+ **Note:
+ ** We use a table for the Hebrew calendar calculation, so the year supported is limited.
+ ============================================================================*/
+
+ private static void CheckHebrewYearValue(int y, int era, String varName)
+ {
+ CheckEraRange(era);
+ if (y > MaxHebrewYear || y < MinHebrewYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ varName,
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MinHebrewYear,
+ MaxHebrewYear));
+ }
+ }
+
+ /*=================================CheckHebrewMonthValue==========================
+ **Action: Check if the Hebrew month value is valid.
+ **Returns: None.
+ **Arguments: year Hebrew year value
+ ** month Hebrew month value
+ **Exceptions: ArgumentOutOfRange_Range if the month value is not valid.
+ **Note:
+ ** Call CheckHebrewYearValue() before calling this to verify the year value is supported.
+ ============================================================================*/
+
+ private void CheckHebrewMonthValue(int year, int month, int era)
+ {
+ int monthsInYear = GetMonthsInYear(year, era);
+ if (month < 1 || month > monthsInYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ monthsInYear));
+ }
+ }
+
+ /*=================================CheckHebrewDayValue==========================
+ **Action: Check if the Hebrew day value is valid.
+ **Returns: None.
+ **Arguments: year Hebrew year value
+ ** month Hebrew month value
+ ** day Hebrew day value.
+ **Exceptions: ArgumentOutOfRange_Range if the day value is not valid.
+ **Note:
+ ** Call CheckHebrewYearValue()/CheckHebrewMonthValue() before calling this to verify the year/month values are valid.
+ ============================================================================*/
+
+ private void CheckHebrewDayValue(int year, int month, int day, int era)
+ {
+ int daysInMonth = GetDaysInMonth(year, month, era);
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ daysInMonth));
+ }
+ }
+
+ internal static void CheckEraRange(int era)
+ {
+ if (era != CurrentEra && era != HebrewEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ }
+
+ private static void CheckTicksRange(long ticks)
+ {
+ if (ticks < calendarMinValue.Ticks || ticks > calendarMaxValue.Ticks)
+ {
+ throw new ArgumentOutOfRangeException(
+ "time",
+ // Print out the date in Gregorian using InvariantCulture since the DateTime is based on GreograinCalendar.
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.ArgumentOutOfRange_CalendarRange,
+ calendarMinValue,
+ calendarMaxValue));
+ }
+ }
+
+ internal static int GetResult(__DateBuffer result, int part)
+ {
+ switch (part)
+ {
+ case DatePartYear:
+ return (result.year);
+ case DatePartMonth:
+ return (result.month);
+ case DatePartDay:
+ return (result.day);
+ }
+
+ throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing);
+ }
+
+ /*=================================GetLunarMonthDay==========================
+ **Action: Using the Hebrew table (HebrewTable) to get the Hebrew month/day value for Gregorian January 1st
+ ** in a given Gregorian year.
+ ** Greogrian January 1st falls usually in Tevet (4th month). Tevet has always 29 days.
+ ** That's why, there no nead to specify the lunar month in the table. There are exceptions, and these
+ ** are coded by giving numbers above 29 and below 1.
+ ** Actual decoding is takenig place in the switch statement below.
+ **Returns:
+ ** The Hebrew year type. The value is from 1 to 6.
+ ** normal years : 1 = 353 days 2 = 354 days 3 = 355 days.
+ ** Leap years : 4 = 383 5 384 6 = 385 days.
+ **Arguments:
+ ** gregorianYear The year value in Gregorian calendar. The value should be between 1500 and 2239.
+ ** lunarDate Object to take the result of the Hebrew year/month/day.
+ **Exceptions:
+ ============================================================================*/
+
+ internal static int GetLunarMonthDay(int gregorianYear, __DateBuffer lunarDate)
+ {
+ //
+ // Get the offset into the LunarMonthLen array and the lunar day
+ // for January 1st.
+ //
+ int index = gregorianYear - FirstGregorianTableYear;
+ if (index < 0 || index > TABLESIZE)
+ {
+ throw new ArgumentOutOfRangeException("gregorianYear");
+ }
+
+ index *= 2;
+ lunarDate.day = s_hebrewTable[index];
+
+ // Get the type of the year. The value is from 1 to 6
+ int LunarYearType = s_hebrewTable[index + 1];
+
+ //
+ // Get the Lunar Month.
+ //
+ switch (lunarDate.day)
+ {
+ case (0): // 1/1 is on Shvat 1
+ lunarDate.month = 5;
+ lunarDate.day = 1;
+ break;
+ case (30): // 1/1 is on Kislev 30
+ lunarDate.month = 3;
+ break;
+ case (31): // 1/1 is on Shvat 2
+ lunarDate.month = 5;
+ lunarDate.day = 2;
+ break;
+ case (32): // 1/1 is on Shvat 3
+ lunarDate.month = 5;
+ lunarDate.day = 3;
+ break;
+ case (33): // 1/1 is on Kislev 29
+ lunarDate.month = 3;
+ lunarDate.day = 29;
+ break;
+ default: // 1/1 is on Tevet (This is the general case)
+ lunarDate.month = 4;
+ break;
+ }
+ return (LunarYearType);
+ }
+
+ // Returns a given date part of this DateTime. This method is used
+ // to compute the year, day-of-year, month, or day part.
+
+ internal virtual int GetDatePart(long ticks, int part)
+ {
+ // The Gregorian year, month, day value for ticks.
+ int gregorianYear, gregorianMonth, gregorianDay;
+ int hebrewYearType; // lunar year type
+ long AbsoluteDate; // absolute date - absolute date 1/1/1600
+
+ //
+ // Make sure we have a valid Gregorian date that will fit into our
+ // Hebrew conversion limits.
+ //
+ CheckTicksRange(ticks);
+
+ DateTime time = new DateTime(ticks);
+
+ //
+ // Save the Gregorian date values.
+ //
+ gregorianYear = time.Year;
+ gregorianMonth = time.Month;
+ gregorianDay = time.Day;
+
+ __DateBuffer lunarDate = new __DateBuffer(); // lunar month and day for Jan 1
+
+ // From the table looking-up value of HebrewTable[index] (stored in lunarDate.day), we get the the
+ // lunar month and lunar day where the Gregorian date 1/1 falls.
+ lunarDate.year = gregorianYear + HebrewYearOf1AD;
+ hebrewYearType = GetLunarMonthDay(gregorianYear, lunarDate);
+
+ // This is the buffer used to store the result Hebrew date.
+ __DateBuffer result = new __DateBuffer();
+
+ //
+ // Store the values for the start of the new year - 1/1.
+ //
+ result.year = lunarDate.year;
+ result.month = lunarDate.month;
+ result.day = lunarDate.day;
+
+ //
+ // Get the absolute date from 1/1/1600.
+ //
+ AbsoluteDate = GregorianCalendar.GetAbsoluteDate(gregorianYear, gregorianMonth, gregorianDay);
+
+ //
+ // If the requested date was 1/1, then we're done.
+ //
+ if ((gregorianMonth == 1) && (gregorianDay == 1))
+ {
+ return (GetResult(result, part));
+ }
+
+ //
+ // Calculate the number of days between 1/1 and the requested date.
+ //
+ long NumDays; // number of days since 1/1
+ NumDays = AbsoluteDate - GregorianCalendar.GetAbsoluteDate(gregorianYear, 1, 1);
+
+ //
+ // If the requested date is within the current lunar month, then
+ // we're done.
+ //
+ if ((NumDays + (long)lunarDate.day) <= (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + lunarDate.month]))
+ {
+ result.day += (int)NumDays;
+ return (GetResult(result, part));
+ }
+
+ //
+ // Adjust for the current partial month.
+ //
+ result.month++;
+ result.day = 1;
+
+ //
+ // Adjust the Lunar Month and Year (if necessary) based on the number
+ // of days between 1/1 and the requested date.
+ //
+ // Assumes Jan 1 can never translate to the last Lunar month, which
+ // is true.
+ //
+ NumDays -= (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + lunarDate.month] - lunarDate.day);
+ Contract.Assert(NumDays >= 1, "NumDays >= 1");
+
+ // If NumDays is 1, then we are done. Otherwise, find the correct Hebrew month
+ // and day.
+ if (NumDays > 1)
+ {
+ //
+ // See if we're on the correct Lunar month.
+ //
+ while (NumDays > (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month]))
+ {
+ //
+ // Adjust the number of days and move to the next month.
+ //
+ NumDays -= (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month++]);
+
+ //
+ // See if we need to adjust the Year.
+ // Must handle both 12 and 13 month years.
+ //
+ if ((result.month > 13) || (s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month] == 0))
+ {
+ //
+ // Adjust the Year.
+ //
+ result.year++;
+ hebrewYearType = s_hebrewTable[(gregorianYear + 1 - FirstGregorianTableYear) * 2 + 1];
+
+ //
+ // Adjust the Month.
+ //
+ result.month = 1;
+ }
+ }
+ //
+ // Found the right Lunar month.
+ //
+ result.day += (int)(NumDays - 1);
+ }
+ return (GetResult(result, part));
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ try
+ {
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+
+
+ int monthsInYear;
+ int i;
+ if (months >= 0)
+ {
+ i = m + months;
+ while (i > (monthsInYear = GetMonthsInYear(y, CurrentEra)))
+ {
+ y++;
+ i -= monthsInYear;
+ }
+ }
+ else
+ {
+ if ((i = m + months) <= 0)
+ {
+ months = -months;
+ months -= m;
+ y--;
+
+ while (months > (monthsInYear = GetMonthsInYear(y, CurrentEra)))
+ {
+ y--;
+ months -= monthsInYear;
+ }
+ monthsInYear = GetMonthsInYear(y, CurrentEra);
+ i = monthsInYear - months;
+ }
+ }
+
+ int days = GetDaysInMonth(y, i);
+ if (d > days)
+ {
+ d = days;
+ }
+ return (new DateTime(ToDateTime(y, i, d, 0, 0, 0, 0).Ticks + (time.Ticks % TicksPerDay)));
+ }
+ // We expect ArgumentException and ArgumentOutOfRangeException (which is subclass of ArgumentException)
+ // If exception is thrown in the calls above, we are out of the supported range of this calendar.
+ catch (ArgumentException)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_AddValue));
+ }
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+
+ y += years;
+ CheckHebrewYearValue(y, Calendar.CurrentEra, "years");
+
+ int months = GetMonthsInYear(y, CurrentEra);
+ if (m > months)
+ {
+ m = months;
+ }
+
+ int days = GetDaysInMonth(y, m);
+ if (d > days)
+ {
+ d = days;
+ }
+
+ long ticks = ToDateTime(y, m, d, 0, 0, 0, 0).Ticks + (time.Ticks % TicksPerDay);
+ Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDay));
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ // If we calculate back, the Hebrew day of week for Gregorian 0001/1/1 is Monday (1).
+ // Therfore, the fomula is:
+ return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+ internal static int GetHebrewYearType(int year, int era)
+ {
+ CheckHebrewYearValue(year, era, "year");
+ // The HebrewTable is indexed by Gregorian year and starts from FirstGregorianYear.
+ // So we need to convert year (Hebrew year value) to Gregorian Year below.
+ return (s_hebrewTable[(year - HebrewYearOf1AD - FirstGregorianTableYear) * 2 + 1]);
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ // Get Hebrew year value of the specified time.
+ int year = GetYear(time);
+ DateTime beginOfYearDate;
+ if (year == 5343)
+ {
+ // Gregorian 1583/01/01 corresponds to Hebrew 5343/04/07 (MinSupportedDateTime)
+ // To figure out the Gregorian date associated with Hebrew 5343/01/01, we need to
+ // count the days from 5343/01/01 to 5343/04/07 and subtract that from Gregorian
+ // 1583/01/01.
+ // 1. Tishri (30 days)
+ // 2. Heshvan (30 days since 5343 has 355 days)
+ // 3. Kislev (30 days since 5343 has 355 days)
+ // 96 days to get from 5343/01/01 to 5343/04/07
+ // Gregorian 1583/01/01 - 96 days = 1582/9/27
+
+ // the beginning of Hebrew year 5343 corresponds to Gregorian September 27, 1582.
+ beginOfYearDate = new DateTime(1582, 9, 27);
+ }
+ else
+ {
+ // following line will fail when year is 5343 (first supported year)
+ beginOfYearDate = ToDateTime(year, 1, 1, 0, 0, 0, 0, CurrentEra);
+ }
+ return ((int)((time.Ticks - beginOfYearDate.Ticks) / TicksPerDay) + 1);
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ CheckEraRange(era);
+ int hebrewYearType = GetHebrewYearType(year, era);
+ CheckHebrewMonthValue(year, month, era);
+
+ Contract.Assert(hebrewYearType >= 1 && hebrewYearType <= 6,
+ "hebrewYearType should be from 1 to 6, but now hebrewYearType = " + hebrewYearType + " for hebrew year " + year);
+ int monthDays = s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + month];
+ if (monthDays == 0)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ return (monthDays);
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ CheckEraRange(era);
+ // normal years : 1 = 353 days 2 = 354 days 3 = 355 days.
+ // Leap years : 4 = 383 5 384 6 = 385 days.
+
+ // LunarYearType is from 1 to 6
+ int LunarYearType = GetHebrewYearType(year, era);
+ if (LunarYearType < 4)
+ {
+ // common year: LunarYearType = 1, 2, 3
+ return (352 + LunarYearType);
+ }
+ return (382 + (LunarYearType - 3));
+ }
+
+ // Returns the era for the specified DateTime value.
+
+ public override int GetEra(DateTime time)
+ {
+ return (HebrewEra);
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { HebrewEra });
+ }
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+ public override int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartMonth));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ return (IsLeapYear(year, era) ? 13 : 12);
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and 9999.
+ //
+
+ public override int GetYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartYear));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ if (IsLeapMonth(year, month, era))
+ {
+ // Every day in a leap month is a leap day.
+ CheckHebrewDayValue(year, month, day, era);
+ return (true);
+ }
+ else if (IsLeapYear(year, Calendar.CurrentEra))
+ {
+ // There is an additional day in the 6th month in the leap year (the extra day is the 30th day in the 6th month),
+ // so we should return true for 6/30 if that's in a leap year.
+ if (month == 6 && day == 30)
+ {
+ return (true);
+ }
+ }
+ CheckHebrewDayValue(year, month, day, era);
+ return (false);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+
+ public override int GetLeapMonth(int year, int era)
+ {
+ // Year/era values are checked in IsLeapYear().
+ if (IsLeapYear(year, era))
+ {
+ // The 7th month in a leap year is a leap month.
+ return (7);
+ }
+ return (0);
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ // Year/era values are checked in IsLeapYear().
+ bool isLeapYear = IsLeapYear(year, era);
+ CheckHebrewMonthValue(year, month, era);
+ // The 7th month in a leap year is a leap month.
+ if (isLeapYear)
+ {
+ if (month == 7)
+ {
+ return (true);
+ }
+ }
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ CheckHebrewYearValue(year, era, "year");
+ return (((7 * (long)year + 1) % 19) < 7);
+ }
+
+ // (month1, day1) - (month2, day2)
+ private static int GetDayDifference(int lunarYearType, int month1, int day1, int month2, int day2)
+ {
+ if (month1 == month2)
+ {
+ return (day1 - day2);
+ }
+
+ // Make sure that (month1, day1) < (month2, day2)
+ bool swap = (month1 > month2);
+ if (swap)
+ {
+ // (month1, day1) < (month2, day2). Swap the values.
+ // The result will be a negative number.
+ int tempMonth, tempDay;
+ tempMonth = month1; tempDay = day1;
+ month1 = month2; day1 = day2;
+ month2 = tempMonth; day2 = tempDay;
+ }
+
+ // Get the number of days from (month1,day1) to (month1, end of month1)
+ int days = s_lunarMonthLen[lunarYearType * MaxMonthPlusOne + month1] - day1;
+
+ // Move to next month.
+ month1++;
+
+ // Add up the days.
+ while (month1 < month2)
+ {
+ days += s_lunarMonthLen[lunarYearType * MaxMonthPlusOne + month1++];
+ }
+ days += day2;
+
+ return (swap ? days : -days);
+ }
+
+ /*=================================HebrewToGregorian==========================
+ **Action: Convert Hebrew date to Gregorian date.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ** The algorithm is like this:
+ ** The hebrew year has an offset to the Gregorian year, so we can guess the Gregorian year for
+ ** the specified Hebrew year. That is, GreogrianYear = HebrewYear - FirstHebrewYearOf1AD.
+ **
+ ** From the Gregorian year and HebrewTable, we can get the Hebrew month/day value
+ ** of the Gregorian date January 1st. Let's call this month/day value [hebrewDateForJan1]
+ **
+ ** If the requested Hebrew month/day is less than [hebrewDateForJan1], we know the result
+ ** Gregorian date falls in previous year. So we decrease the Gregorian year value, and
+ ** retrieve the Hebrew month/day value of the Gregorian date january 1st again.
+ **
+ ** Now, we get the answer of the Gregorian year.
+ **
+ ** The next step is to get the number of days between the requested Hebrew month/day
+ ** and [hebrewDateForJan1]. When we get that, we can create the DateTime by adding/subtracting
+ ** the ticks value of the number of days.
+ **
+ ============================================================================*/
+
+
+ private static DateTime HebrewToGregorian(int hebrewYear, int hebrewMonth, int hebrewDay, int hour, int minute, int second, int millisecond)
+ {
+ // Get the rough Gregorian year for the specified hebrewYear.
+ //
+ int gregorianYear = hebrewYear - HebrewYearOf1AD;
+
+ __DateBuffer hebrewDateOfJan1 = new __DateBuffer(); // year value is unused.
+ int lunarYearType = GetLunarMonthDay(gregorianYear, hebrewDateOfJan1);
+
+ if ((hebrewMonth == hebrewDateOfJan1.month) && (hebrewDay == hebrewDateOfJan1.day))
+ {
+ return (new DateTime(gregorianYear, 1, 1, hour, minute, second, millisecond));
+ }
+
+ int days = GetDayDifference(lunarYearType, hebrewMonth, hebrewDay, hebrewDateOfJan1.month, hebrewDateOfJan1.day);
+
+ DateTime gregorianNewYear = new DateTime(gregorianYear, 1, 1);
+ return (new DateTime(gregorianNewYear.Ticks + days * TicksPerDay
+ + TimeToTicks(hour, minute, second, millisecond)));
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ CheckHebrewYearValue(year, era, "year");
+ CheckHebrewMonthValue(year, month, era);
+ CheckHebrewDayValue(year, month, day, era);
+ DateTime dt = HebrewToGregorian(year, month, day, hour, minute, second, millisecond);
+ CheckTicksRange(dt.Ticks);
+ return (dt);
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 5790;
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value == 99)
+ {
+ // Do nothing here. Year 99 is allowed so that TwoDitYearMax is disabled.
+ }
+ else
+ {
+ CheckHebrewYearValue(value, HebrewEra, "value");
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year < 100)
+ {
+ return (base.ToFourDigitYear(year));
+ }
+
+ if (year > MaxHebrewYear || year < MinHebrewYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MinHebrewYear,
+ MaxHebrewYear));
+ }
+ return (year);
+ }
+
+ internal class __DateBuffer
+ {
+ internal int year;
+ internal int month;
+ internal int day;
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/HebrewNumber.cs b/src/mscorlib/corefx/System/Globalization/HebrewNumber.cs
new file mode 100644
index 0000000000..8fc264b788
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/HebrewNumber.cs
@@ -0,0 +1,465 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using Debug = BCLDebug;
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Used in HebrewNumber.ParseByChar to maintain the context information (
+ // the state in the state machine and current Hebrew number values, etc.)
+ // when parsing Hebrew number character by character.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal struct HebrewNumberParsingContext
+ {
+ // The current state of the state machine for parsing Hebrew numbers.
+ internal HebrewNumber.HS state;
+ // The current value of the Hebrew number.
+ // The final value is determined when state is FoundEndOfHebrewNumber.
+ internal int result;
+
+ public HebrewNumberParsingContext(int result)
+ {
+ // Set the start state of the state machine for parsing Hebrew numbers.
+ state = HebrewNumber.HS.Start;
+ this.result = result;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Please see ParseByChar() for comments about different states defined here.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal enum HebrewNumberParsingState
+ {
+ InvalidHebrewNumber,
+ NotHebrewDigit,
+ FoundEndOfHebrewNumber,
+ ContinueParsing,
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // class HebrewNumber
+ //
+ // Provides static methods for formatting integer values into
+ // Hebrew text and parsing Hebrew number text.
+ //
+ // Limitations:
+ // Parse can only handles value 1 ~ 999.
+ // ToString() can only handles 1 ~ 999. If value is greater than 5000,
+ // 5000 will be subtracted from the value.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal class HebrewNumber
+ {
+ // This class contains only static methods. Add a private ctor so that
+ // compiler won't generate a default one for us.
+ private HebrewNumber()
+ {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Converts the given number to Hebrew letters according to the numeric
+ // value of each Hebrew letter. Basically, this converts the lunar year
+ // and the lunar month to letters.
+ //
+ // The character of a year is described by three letters of the Hebrew
+ // alphabet, the first and third giving, respectively, the days of the
+ // weeks on which the New Year occurs and Passover begins, while the
+ // second is the initial of the Hebrew word for defective, normal, or
+ // complete.
+ //
+ // Defective Year : Both Heshvan and Kislev are defective (353 or 383 days)
+ // Normal Year : Heshvan is defective, Kislev is full (354 or 384 days)
+ // Complete Year : Both Heshvan and Kislev are full (355 or 385 days)
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal static String ToString(int Number)
+ {
+ char cTens = '\x0';
+ char cUnits; // tens and units chars
+ int Hundreds, Tens; // hundreds and tens values
+ StringBuilder szHebrew = new StringBuilder();
+
+
+ //
+ // Adjust the number if greater than 5000.
+ //
+ if (Number > 5000)
+ {
+ Number -= 5000;
+ }
+
+ Contract.Assert(Number > 0 && Number <= 999, "Number is out of range."); ;
+
+ //
+ // Get the Hundreds.
+ //
+ Hundreds = Number / 100;
+
+ if (Hundreds > 0)
+ {
+ Number -= Hundreds * 100;
+ // \x05e7 = 100
+ // \x05e8 = 200
+ // \x05e9 = 300
+ // \x05ea = 400
+ // If the number is greater than 400, use the multiples of 400.
+ for (int i = 0; i < (Hundreds / 4); i++)
+ {
+ szHebrew.Append('\x05ea');
+ }
+
+ int remains = Hundreds % 4;
+ if (remains > 0)
+ {
+ szHebrew.Append((char)((int)'\x05e6' + remains));
+ }
+ }
+
+ //
+ // Get the Tens.
+ //
+ Tens = Number / 10;
+ Number %= 10;
+
+ switch (Tens)
+ {
+ case (0):
+ cTens = '\x0';
+ break;
+ case (1):
+ cTens = '\x05d9'; // Hebrew Letter Yod
+ break;
+ case (2):
+ cTens = '\x05db'; // Hebrew Letter Kaf
+ break;
+ case (3):
+ cTens = '\x05dc'; // Hebrew Letter Lamed
+ break;
+ case (4):
+ cTens = '\x05de'; // Hebrew Letter Mem
+ break;
+ case (5):
+ cTens = '\x05e0'; // Hebrew Letter Nun
+ break;
+ case (6):
+ cTens = '\x05e1'; // Hebrew Letter Samekh
+ break;
+ case (7):
+ cTens = '\x05e2'; // Hebrew Letter Ayin
+ break;
+ case (8):
+ cTens = '\x05e4'; // Hebrew Letter Pe
+ break;
+ case (9):
+ cTens = '\x05e6'; // Hebrew Letter Tsadi
+ break;
+ }
+
+ //
+ // Get the Units.
+ //
+ cUnits = (char)(Number > 0 ? ((int)'\x05d0' + Number - 1) : 0);
+
+ if ((cUnits == '\x05d4') && // Hebrew Letter He (5)
+ (cTens == '\x05d9'))
+ { // Hebrew Letter Yod (10)
+ cUnits = '\x05d5'; // Hebrew Letter Vav (6)
+ cTens = '\x05d8'; // Hebrew Letter Tet (9)
+ }
+
+ if ((cUnits == '\x05d5') && // Hebrew Letter Vav (6)
+ (cTens == '\x05d9'))
+ { // Hebrew Letter Yod (10)
+ cUnits = '\x05d6'; // Hebrew Letter Zayin (7)
+ cTens = '\x05d8'; // Hebrew Letter Tet (9)
+ }
+
+ //
+ // Copy the appropriate info to the given buffer.
+ //
+
+ if (cTens != '\x0')
+ {
+ szHebrew.Append(cTens);
+ }
+
+ if (cUnits != '\x0')
+ {
+ szHebrew.Append(cUnits);
+ }
+
+ if (szHebrew.Length > 1)
+ {
+ szHebrew.Insert(szHebrew.Length - 1, '"');
+ }
+ else
+ {
+ szHebrew.Append('\'');
+ }
+
+ //
+ // Return success.
+ //
+ return (szHebrew.ToString());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Token used to tokenize a Hebrew word into tokens so that we can use in the
+ // state machine.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private enum HebrewToken : short
+ {
+ Invalid = -1,
+ Digit400 = 0,
+ Digit200_300 = 1,
+ Digit100 = 2,
+ Digit10 = 3, // 10 ~ 90
+ Digit1 = 4, // 1, 2, 3, 4, 5, 8,
+ Digit6_7 = 5,
+ Digit7 = 6,
+ Digit9 = 7,
+ SingleQuote = 8,
+ DoubleQuote = 9,
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // This class is used to map a token into its Hebrew digit value.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private struct HebrewValue
+ {
+ internal HebrewToken token;
+ internal short value;
+ internal HebrewValue(HebrewToken token, short value)
+ {
+ this.token = token;
+ this.value = value;
+ }
+ }
+
+ //
+ // Map a Hebrew character from U+05D0 ~ U+05EA to its digit value.
+ // The value is -1 if the Hebrew character does not have a associated value.
+ //
+ private static readonly HebrewValue[] s_hebrewValues = {
+ new HebrewValue(HebrewToken.Digit1, 1) , // '\x05d0
+ new HebrewValue(HebrewToken.Digit1, 2) , // '\x05d1
+ new HebrewValue(HebrewToken.Digit1, 3) , // '\x05d2
+ new HebrewValue(HebrewToken.Digit1, 4) , // '\x05d3
+ new HebrewValue(HebrewToken.Digit1, 5) , // '\x05d4
+ new HebrewValue(HebrewToken.Digit6_7,6) , // '\x05d5
+ new HebrewValue(HebrewToken.Digit6_7,7) , // '\x05d6
+ new HebrewValue(HebrewToken.Digit1, 8) , // '\x05d7
+ new HebrewValue(HebrewToken.Digit9, 9) , // '\x05d8
+ new HebrewValue(HebrewToken.Digit10, 10) , // '\x05d9; // Hebrew Letter Yod
+ new HebrewValue(HebrewToken.Invalid, -1) , // '\x05da;
+ new HebrewValue(HebrewToken.Digit10, 20) , // '\x05db; // Hebrew Letter Kaf
+ new HebrewValue(HebrewToken.Digit10, 30) , // '\x05dc; // Hebrew Letter Lamed
+ new HebrewValue(HebrewToken.Invalid, -1) , // '\x05dd;
+ new HebrewValue(HebrewToken.Digit10, 40) , // '\x05de; // Hebrew Letter Mem
+ new HebrewValue(HebrewToken.Invalid, -1) , // '\x05df;
+ new HebrewValue(HebrewToken.Digit10, 50) , // '\x05e0; // Hebrew Letter Nun
+ new HebrewValue(HebrewToken.Digit10, 60) , // '\x05e1; // Hebrew Letter Samekh
+ new HebrewValue(HebrewToken.Digit10, 70) , // '\x05e2; // Hebrew Letter Ayin
+ new HebrewValue(HebrewToken.Invalid, -1) , // '\x05e3;
+ new HebrewValue(HebrewToken.Digit10, 80) , // '\x05e4; // Hebrew Letter Pe
+ new HebrewValue(HebrewToken.Invalid, -1) , // '\x05e5;
+ new HebrewValue(HebrewToken.Digit10, 90) , // '\x05e6; // Hebrew Letter Tsadi
+ new HebrewValue(HebrewToken.Digit100, 100) , // '\x05e7;
+ new HebrewValue(HebrewToken.Digit200_300, 200) , // '\x05e8;
+ new HebrewValue(HebrewToken.Digit200_300, 300) , // '\x05e9;
+ new HebrewValue(HebrewToken.Digit400, 400) , // '\x05ea;
+ };
+
+ private const int minHebrewNumberCh = 0x05d0;
+ private static char s_maxHebrewNumberCh = (char)(minHebrewNumberCh + s_hebrewValues.Length - 1);
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Hebrew number parsing State
+ // The current state and the next token will lead to the next state in the state machine.
+ // DQ = Double Quote
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ internal enum HS : sbyte
+ {
+ _err = -1, // an error state
+ Start = 0,
+ S400 = 1, // a Hebrew digit 400
+ S400_400 = 2, // Two Hebrew digit 400
+ S400_X00 = 3, // Two Hebrew digit 400 and followed by 100
+ S400_X0 = 4, // Hebrew digit 400 and followed by 10 ~ 90
+ X00_DQ = 5, // A hundred number and followed by a double quote.
+ S400_X00_X0 = 6,
+ X0_DQ = 7, // A two-digit number and followed by a double quote.
+ X = 8, // A single digit Hebrew number.
+ X0 = 9, // A two-digit Hebrew number
+ X00 = 10, // A three-digit Hebrew number
+ S400_DQ = 11, // A Hebrew digit 400 and followed by a double quote.
+ S400_400_DQ = 12,
+ S400_400_100 = 13,
+ S9 = 14, // Hebrew digit 9
+ X00_S9 = 15, // A hundered number and followed by a digit 9
+ S9_DQ = 16, // Hebrew digit 9 and followed by a double quote
+ END = 100, // A terminial state is reached.
+ }
+
+ //
+ // The state machine for Hebrew number pasing.
+ //
+ private readonly static HS[] s_numberPasingState =
+ {
+ // 400 300/200 100 90~10 8~1 6, 7, 9, ' "
+ /* 0 */
+ HS.S400, HS.X00, HS.X00, HS.X0, HS.X, HS.X, HS.X, HS.S9, HS._err, HS._err,
+ /* 1: S400 */
+ HS.S400_400, HS.S400_X00, HS.S400_X00, HS.S400_X0, HS._err, HS._err, HS._err, HS.X00_S9 ,HS.END, HS.S400_DQ,
+ /* 2: S400_400 */
+ HS._err, HS._err, HS.S400_400_100,HS.S400_X0, HS._err, HS._err, HS._err, HS.X00_S9 ,HS._err, HS.S400_400_DQ,
+ /* 3: S400_X00 */
+ HS._err, HS._err, HS._err, HS.S400_X00_X0, HS._err, HS._err, HS._err, HS.X00_S9 ,HS._err, HS.X00_DQ,
+ /* 4: S400_X0 */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.X0_DQ,
+ /* 5: X00_DQ */
+ HS._err, HS._err, HS._err, HS.END, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err,
+ /* 6: S400_X00_X0 */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.X0_DQ,
+ /* 7: X0_DQ */
+ HS._err, HS._err, HS._err, HS._err, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err,
+ /* 8: X */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS._err,
+ /* 9: X0 */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS.X0_DQ,
+ /* 10: X00 */
+ HS._err, HS._err, HS._err, HS.S400_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS.END, HS.X00_DQ,
+ /* 11: S400_DQ */
+ HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err,
+ /* 12: S400_400_DQ*/
+ HS._err, HS._err, HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err,
+ /* 13: S400_400_100*/
+ HS._err, HS._err, HS._err, HS.S400_X00_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS._err, HS.X00_DQ,
+ /* 14: S9 */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS.S9_DQ,
+ /* 15: X00_S9 */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.S9_DQ,
+ /* 16: S9_DQ */
+ HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS.END, HS._err, HS._err, HS._err
+ };
+
+ // Count of valid HebrewToken, column count in the NumberPasingState array
+ private const int HebrewTokenCount = 10;
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Actions:
+ // Parse the Hebrew number by passing one character at a time.
+ // The state between characters are maintained at HebrewNumberPasingContext.
+ // Returns:
+ // Return a enum of HebrewNumberParsingState.
+ // NotHebrewDigit: The specified ch is not a valid Hebrew digit.
+ // InvalidHebrewNumber: After parsing the specified ch, it will lead into
+ // an invalid Hebrew number text.
+ // FoundEndOfHebrewNumber: A terminal state is reached. This means that
+ // we find a valid Hebrew number text after the specified ch is parsed.
+ // ContinueParsing: The specified ch is a valid Hebrew digit, and
+ // it will lead into a valid state in the state machine, we should
+ // continue to parse incoming characters.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static HebrewNumberParsingState ParseByChar(char ch, ref HebrewNumberParsingContext context)
+ {
+ Debug.Assert(s_numberPasingState.Length == HebrewTokenCount * ((int)HS.S9_DQ + 1));
+
+ HebrewToken token;
+ if (ch == '\'')
+ {
+ token = HebrewToken.SingleQuote;
+ }
+ else if (ch == '\"')
+ {
+ token = HebrewToken.DoubleQuote;
+ }
+ else
+ {
+ int index = (int)ch - minHebrewNumberCh;
+ if (index >= 0 && index < s_hebrewValues.Length)
+ {
+ token = s_hebrewValues[index].token;
+ if (token == HebrewToken.Invalid)
+ {
+ return (HebrewNumberParsingState.NotHebrewDigit);
+ }
+ context.result += s_hebrewValues[index].value;
+ }
+ else
+ {
+ // Not in valid Hebrew digit range.
+ return (HebrewNumberParsingState.NotHebrewDigit);
+ }
+ }
+ context.state = s_numberPasingState[(int)context.state * (int)HebrewTokenCount + (int)token];
+ if (context.state == HS._err)
+ {
+ // Invalid Hebrew state. This indicates an incorrect Hebrew number.
+ return (HebrewNumberParsingState.InvalidHebrewNumber);
+ }
+ if (context.state == HS.END)
+ {
+ // Reach a terminal state.
+ return (HebrewNumberParsingState.FoundEndOfHebrewNumber);
+ }
+ // We should continue to parse.
+ return (HebrewNumberParsingState.ContinueParsing);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Actions:
+ // Check if the ch is a valid Hebrew number digit.
+ // This function will return true if the specified char is a legal Hebrew
+ // digit character, single quote, or double quote.
+ // Returns:
+ // true if the specified character is a valid Hebrew number character.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static bool IsDigit(char ch)
+ {
+ if (ch >= minHebrewNumberCh && ch <= s_maxHebrewNumberCh)
+ {
+ return (s_hebrewValues[ch - minHebrewNumberCh].value >= 0);
+ }
+ return (ch == '\'' || ch == '\"');
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/HijriCalendar.Unix.cs b/src/mscorlib/corefx/System/Globalization/HijriCalendar.Unix.cs
new file mode 100644
index 0000000000..a6e8f73d3e
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/HijriCalendar.Unix.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Globalization
+{
+ public partial class HijriCalendar : Calendar
+ {
+ private static int GetHijriDateAdjustment()
+ {
+ // this setting is not supported on Unix, so always return 0
+ return 0;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/HijriCalendar.Windows.cs b/src/mscorlib/corefx/System/Globalization/HijriCalendar.Windows.cs
new file mode 100644
index 0000000000..185c5184be
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/HijriCalendar.Windows.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.Runtime.Augments;
+
+namespace System.Globalization
+{
+ public partial class HijriCalendar : Calendar
+ {
+ public static int GetHijriDateAdjustment()
+ {
+ return WinRTInterop.Callbacks.GetHijriDateAdjustment();
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/HijriCalendar.cs b/src/mscorlib/corefx/System/Globalization/HijriCalendar.cs
new file mode 100644
index 0000000000..72d9ab3f52
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/HijriCalendar.cs
@@ -0,0 +1,675 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.Versioning;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Rules for the Hijri calendar:
+ // - The Hijri calendar is a strictly Lunar calendar.
+ // - Days begin at sunset.
+ // - Islamic Year 1 (Muharram 1, 1 A.H.) is equivalent to absolute date
+ // 227015 (Friday, July 16, 622 C.E. - Julian).
+ // - Leap Years occur in the 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, & 29th
+ // years of a 30-year cycle. Year = leap iff ((11y+14) mod 30 < 11).
+ // - There are 12 months which contain alternately 30 and 29 days.
+ // - The 12th month, Dhu al-Hijjah, contains 30 days instead of 29 days
+ // in a leap year.
+ // - Common years have 354 days. Leap years have 355 days.
+ // - There are 10,631 days in a 30-year cycle.
+ // - The Islamic months are:
+ // 1. Muharram (30 days) 7. Rajab (30 days)
+ // 2. Safar (29 days) 8. Sha'ban (29 days)
+ // 3. Rabi I (30 days) 9. Ramadan (30 days)
+ // 4. Rabi II (29 days) 10. Shawwal (29 days)
+ // 5. Jumada I (30 days) 11. Dhu al-Qada (30 days)
+ // 6. Jumada II (29 days) 12. Dhu al-Hijjah (29 days) {30}
+ //
+ // NOTENOTE
+ // The calculation of the HijriCalendar is based on the absolute date. And the
+ // absolute date means the number of days from January 1st, 1 A.D.
+ // Therefore, we do not support the days before the January 1st, 1 A.D.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 0622/07/18 9999/12/31
+ ** Hijri 0001/01/01 9666/04/03
+ */
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class HijriCalendar : Calendar
+ {
+ internal static readonly int HijriEra = 1;
+
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+
+ internal const int MinAdvancedHijri = -2;
+ internal const int MaxAdvancedHijri = 2;
+
+ internal static readonly int[] HijriMonthDays = { 0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355 };
+
+ private int _hijriAdvance = Int32.MinValue;
+
+ // DateTime.MaxValue = Hijri calendar (year:9666, month: 4, day: 3).
+ internal const int MaxCalendarYear = 9666;
+ internal const int MaxCalendarMonth = 4;
+ internal const int MaxCalendarDay = 3;
+ // Hijri calendar (year: 1, month: 1, day:1 ) = Gregorian (year: 622, month: 7, day: 18)
+ // This is the minimal Gregorian date that we support in the HijriCalendar.
+ internal static readonly DateTime calendarMinValue = new DateTime(622, 7, 18);
+ internal static readonly DateTime calendarMaxValue = DateTime.MaxValue;
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (calendarMinValue);
+ }
+ }
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (calendarMaxValue);
+ }
+ }
+
+ public HijriCalendar()
+ {
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return CalendarId.HIJRI;
+ }
+ }
+
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // the year before the 1st year of the cycle would have been the 30th year
+ // of the previous cycle which is not a leap year. Common years have 354 days.
+ return 354;
+ }
+ }
+
+
+
+ /*=================================GetAbsoluteDateHijri==========================
+ **Action: Gets the Absolute date for the given Hijri date. The absolute date means
+ ** the number of days from January 1st, 1 A.D.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+ private long GetAbsoluteDateHijri(int y, int m, int d)
+ {
+ return (long)(DaysUpToHijriYear(y) + HijriMonthDays[m - 1] + d - 1 - HijriAdjustment);
+ }
+
+ /*=================================DaysUpToHijriYear==========================
+ **Action: Gets the total number of days (absolute date) up to the given Hijri Year.
+ ** The absolute date means the number of days from January 1st, 1 A.D.
+ **Returns: Gets the total number of days (absolute date) up to the given Hijri Year.
+ **Arguments: HijriYear year value in Hijri calendar.
+ **Exceptions: None
+ **Notes:
+ ============================================================================*/
+
+ private long DaysUpToHijriYear(int HijriYear)
+ {
+ long NumDays; // number of absolute days
+ int NumYear30; // number of years up to current 30 year cycle
+ int NumYearsLeft; // number of years into 30 year cycle
+
+ //
+ // Compute the number of years up to the current 30 year cycle.
+ //
+ NumYear30 = ((HijriYear - 1) / 30) * 30;
+
+ //
+ // Compute the number of years left. This is the number of years
+ // into the 30 year cycle for the given year.
+ //
+ NumYearsLeft = HijriYear - NumYear30 - 1;
+
+ //
+ // Compute the number of absolute days up to the given year.
+ //
+ NumDays = ((NumYear30 * 10631L) / 30L) + 227013L;
+ while (NumYearsLeft > 0)
+ {
+ // Common year is 354 days, and leap year is 355 days.
+ NumDays += 354 + (IsLeapYear(NumYearsLeft, CurrentEra) ? 1 : 0);
+ NumYearsLeft--;
+ }
+
+ //
+ // Return the number of absolute days.
+ //
+ return (NumDays);
+ }
+
+ public int HijriAdjustment
+ {
+ get
+ {
+ if (_hijriAdvance == Int32.MinValue)
+ {
+ // Never been set before. Use the system value from registry.
+ _hijriAdvance = GetHijriDateAdjustment();
+ }
+ return (_hijriAdvance);
+ }
+
+ set
+ {
+ // NOTE: Check the value of Min/MaxAdavncedHijri with Arabic speakers to see if the assumption is good.
+ if (value < MinAdvancedHijri || value > MaxAdvancedHijri)
+ {
+ throw new ArgumentOutOfRangeException(
+ "HijriAdjustment",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Bounds_Lower_Upper,
+ MinAdvancedHijri,
+ MaxAdvancedHijri));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+
+ _hijriAdvance = value;
+ }
+ }
+
+ internal static void CheckTicksRange(long ticks)
+ {
+ if (ticks < calendarMinValue.Ticks || ticks > calendarMaxValue.Ticks)
+ {
+ throw new ArgumentOutOfRangeException(
+ "time",
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.ArgumentOutOfRange_CalendarRange,
+ calendarMinValue,
+ calendarMaxValue));
+ }
+ }
+
+ internal static void CheckEraRange(int era)
+ {
+ if (era != CurrentEra && era != HijriEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ }
+
+ internal static void CheckYearRange(int year, int era)
+ {
+ CheckEraRange(era);
+ if (year < 1 || year > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxCalendarYear));
+ }
+ }
+
+ internal static void CheckYearMonthRange(int year, int month, int era)
+ {
+ CheckYearRange(year, era);
+ if (year == MaxCalendarYear)
+ {
+ if (month > MaxCalendarMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxCalendarMonth));
+ }
+ }
+
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ }
+
+ /*=================================GetDatePart==========================
+ **Action: Returns a given date part of this <i>DateTime</i>. This method is used
+ ** to compute the year, day-of-year, month, or day part.
+ **Returns:
+ **Arguments:
+ **Exceptions: ArgumentException if part is incorrect.
+ **Notes:
+ ** First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks.
+ ** Use the formula (((AbsoluteDate - 227013) * 30) / 10631) + 1, we can a rough value for the Hijri year.
+ ** In order to get the exact Hijri year, we compare the exact absolute date for HijriYear and (HijriYear + 1).
+ ** From here, we can get the correct Hijri year.
+ ============================================================================*/
+
+ internal virtual int GetDatePart(long ticks, int part)
+ {
+ int HijriYear; // Hijri year
+ int HijriMonth; // Hijri month
+ int HijriDay; // Hijri day
+ long NumDays; // The calculation buffer in number of days.
+
+ CheckTicksRange(ticks);
+
+ //
+ // Get the absolute date. The absolute date is the number of days from January 1st, 1 A.D.
+ // 1/1/0001 is absolute date 1.
+ //
+ NumDays = ticks / GregorianCalendar.TicksPerDay + 1;
+
+ //
+ // See how much we need to backup or advance
+ //
+ NumDays += HijriAdjustment;
+
+ //
+ // Calculate the appromixate Hijri Year from this magic formula.
+ //
+ HijriYear = (int)(((NumDays - 227013) * 30) / 10631) + 1;
+
+ long daysToHijriYear = DaysUpToHijriYear(HijriYear); // The absoulte date for HijriYear
+ long daysOfHijriYear = GetDaysInYear(HijriYear, CurrentEra); // The number of days for (HijriYear+1) year.
+
+ if (NumDays < daysToHijriYear)
+ {
+ daysToHijriYear -= daysOfHijriYear;
+ HijriYear--;
+ }
+ else if (NumDays == daysToHijriYear)
+ {
+ HijriYear--;
+ daysToHijriYear -= GetDaysInYear(HijriYear, CurrentEra);
+ }
+ else
+ {
+ if (NumDays > daysToHijriYear + daysOfHijriYear)
+ {
+ daysToHijriYear += daysOfHijriYear;
+ HijriYear++;
+ }
+ }
+ if (part == DatePartYear)
+ {
+ return (HijriYear);
+ }
+
+ //
+ // Calculate the Hijri Month.
+ //
+
+ HijriMonth = 1;
+ NumDays -= daysToHijriYear;
+
+ if (part == DatePartDayOfYear)
+ {
+ return ((int)NumDays);
+ }
+
+ while ((HijriMonth <= 12) && (NumDays > HijriMonthDays[HijriMonth - 1]))
+ {
+ HijriMonth++;
+ }
+ HijriMonth--;
+
+ if (part == DatePartMonth)
+ {
+ return (HijriMonth);
+ }
+
+ //
+ // Calculate the Hijri Day.
+ //
+ HijriDay = (int)(NumDays - HijriMonthDays[HijriMonth - 1]);
+
+ if (part == DatePartDay)
+ {
+ return (HijriDay);
+ }
+ // Incorrect part value.
+ throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing);
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ -120000,
+ 120000));
+ }
+ Contract.EndContractBlock();
+ // Get the date in Hijri calendar.
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+ int i = m - 1 + months;
+ if (i >= 0)
+ {
+ m = i % 12 + 1;
+ y = y + i / 12;
+ }
+ else
+ {
+ m = 12 + (i + 1) % 12;
+ y = y + (i - 11) / 12;
+ }
+ int days = GetDaysInMonth(y, m);
+ if (d > days)
+ {
+ d = days;
+ }
+ long ticks = GetAbsoluteDateHijri(y, m, d) * TicksPerDay + (time.Ticks % TicksPerDay);
+ Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (AddMonths(time, years * 12));
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDay));
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDayOfYear));
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+ [Pure]
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ CheckYearMonthRange(year, month, era);
+ if (month == 12)
+ {
+ // For the 12th month, leap year has 30 days, and common year has 29 days.
+ return (IsLeapYear(year, CurrentEra) ? 30 : 29);
+ }
+ // Other months contain 30 and 29 days alternatively. The 1st month has 30 days.
+ return (((month % 2) == 1) ? 30 : 29);
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ // Common years have 354 days. Leap years have 355 days.
+ return (IsLeapYear(year, CurrentEra) ? 355 : 354);
+ }
+
+ // Returns the era for the specified DateTime value.
+
+ public override int GetEra(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return (HijriEra);
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { HijriEra });
+ }
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+ public override int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartMonth));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return (12);
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and MaxCalendarYear.
+ //
+
+ public override int GetYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartYear));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ // The year/month/era value checking is done in GetDaysInMonth().
+ int daysInMonth = GetDaysInMonth(year, month, era);
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Day,
+ daysInMonth,
+ month));
+ }
+ return (IsLeapYear(year, era) && month == 12 && day == 30);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return (0);
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ CheckYearMonthRange(year, month, era);
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return ((((year * 11) + 14) % 30) < 11);
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ // The year/month/era checking is done in GetDaysInMonth().
+ int daysInMonth = GetDaysInMonth(year, month, era);
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Day,
+ daysInMonth,
+ month));
+ }
+
+ long lDate = GetAbsoluteDateHijri(year, month, day);
+
+ if (lDate >= 0)
+ {
+ return (new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond)));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 1451;
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "value",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ MaxCalendarYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year < 100)
+ {
+ return (base.ToFourDigitYear(year));
+ }
+
+ if (year > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxCalendarYear));
+ }
+ return (year);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/InternalGlobalizationHelper.cs b/src/mscorlib/corefx/System/Globalization/InternalGlobalizationHelper.cs
new file mode 100644
index 0000000000..0a4e6f0600
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/InternalGlobalizationHelper.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ internal class InternalGloablizationHelper
+ {
+ // Copied from the TimeSpan to be used inside the globalization code and avoid internal dependancy on TimeSpan class
+ internal static long TimeToTicks(int hour, int minute, int second)
+ {
+ // totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31,
+ // which is less than 2^44, meaning we won't overflow totalSeconds.
+ long totalSeconds = (long)hour * 3600 + (long)minute * 60 + (long)second;
+ if (totalSeconds > MaxSeconds || totalSeconds < MinSeconds)
+ throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong);
+ return totalSeconds * TicksPerSecond;
+ }
+
+
+ //
+ // Define needed constants so globalization code can be independant from any other types
+ //
+
+ internal const long TicksPerMillisecond = 10000;
+ internal const long TicksPerTenthSecond = TicksPerMillisecond * 100;
+ internal const long TicksPerSecond = TicksPerMillisecond * 1000; // 10,000,000
+ internal const long MaxSeconds = Int64.MaxValue / TicksPerSecond;
+ internal const long MinSeconds = Int64.MinValue / TicksPerSecond;
+ private const int DaysPerYear = 365;
+ private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461
+ private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524
+ private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097
+ private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059
+ private const long TicksPerMinute = TicksPerSecond * 60;
+ private const long TicksPerHour = TicksPerMinute * 60;
+ private const long TicksPerDay = TicksPerHour * 24;
+ internal const long MaxTicks = DaysTo10000 * TicksPerDay - 1;
+ internal const long MinTicks = 0;
+ internal const long MaxMilliSeconds = Int64.MaxValue / TicksPerMillisecond;
+ internal const long MinMilliSeconds = Int64.MinValue / TicksPerMillisecond;
+
+ internal const int StringBuilderDefaultCapacity = 16;
+
+ internal const Int64 MaxOffset = TimeSpan.TicksPerHour * 14;
+ internal const Int64 MinOffset = -MaxOffset;
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Unix.cs b/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Unix.cs
new file mode 100644
index 0000000000..12f430c71c
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Unix.cs
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Security;
+
+namespace System.Globalization
+{
+ public partial class JapaneseCalendar : Calendar
+ {
+ [SecuritySafeCritical]
+ private static EraInfo[] GetJapaneseEras()
+ {
+ string[] eraNames;
+ if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames))
+ {
+ return null;
+ }
+
+ string[] abbrevEnglishEraNames;
+ if (!CalendarData.EnumCalendarInfo("en", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames))
+ {
+ return null;
+ }
+
+ List<EraInfo> eras = new List<EraInfo>();
+ int lastMaxYear = GregorianCalendar.MaxYear;
+
+ int latestEra = Interop.GlobalizationInterop.GetLatestJapaneseEra();
+ for (int i = latestEra; i >= 0; i--)
+ {
+ DateTime dt;
+ if (!GetJapaneseEraStartDate(i, out dt))
+ {
+ return null;
+ }
+
+ if (dt < JapaneseCalendar.calendarMinValue)
+ {
+ // only populate the Eras that are valid JapaneseCalendar date times
+ break;
+ }
+
+ eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1,
+ eraNames[i], GetAbbreviatedEraName(eraNames, i), abbrevEnglishEraNames[i]));
+
+ lastMaxYear = dt.Year;
+ }
+
+ // remap the Era numbers, now that we know how many there will be
+ for (int i = 0; i < eras.Count; i++)
+ {
+ eras[i].era = eras.Count - i;
+ }
+
+ return eras.ToArray();
+ }
+
+ // PAL Layer ends here
+
+ private static string GetAbbreviatedEraName(string[] eraNames, int eraIndex)
+ {
+ // This matches the behavior on Win32 - only returning the first character of the era name.
+ // See Calendar.EraAsString(Int32) - https://msdn.microsoft.com/en-us/library/windows/apps/br206751.aspx
+ return eraNames[eraIndex].Substring(0, 1);
+ }
+
+ [SecuritySafeCritical]
+ private static bool GetJapaneseEraStartDate(int era, out DateTime dateTime)
+ {
+ dateTime = default(DateTime);
+
+ int startYear;
+ int startMonth;
+ int startDay;
+ bool result = Interop.GlobalizationInterop.GetJapaneseEraStartDate(
+ era,
+ out startYear,
+ out startMonth,
+ out startDay);
+
+ if (result)
+ {
+ dateTime = new DateTime(startYear, startMonth, startDay);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Windows.cs b/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Windows.cs
new file mode 100644
index 0000000000..6a9df97200
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Windows.cs
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+
+using Internal.Runtime.Augments;
+
+namespace System.Globalization
+{
+ public partial class JapaneseCalendar : Calendar
+ {
+ private static EraInfo[] GetJapaneseEras()
+ {
+ int erasCount = WinRTInterop.Callbacks.GetJapaneseEraCount();
+ if (erasCount < 4)
+ {
+ return null;
+ }
+
+ EraInfo[] eras = new EraInfo[erasCount];
+ int lastMaxYear = GregorianCalendar.MaxYear;
+
+ for (int i = erasCount; i > 0; i--)
+ {
+ DateTimeOffset dateOffset;
+
+ string eraName;
+ string abbreviatedEraName;
+
+ if (!GetJapaneseEraInfo(i, out dateOffset, out eraName, out abbreviatedEraName))
+ {
+ return null;
+ }
+
+ DateTime dt = new DateTime(dateOffset.Ticks);
+
+ eras[erasCount - i] = new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1,
+ eraName, abbreviatedEraName, GetJapaneseEnglishEraName(i)); // era #4 start year/month/day, yearOffset, minEraYear
+
+ lastMaxYear = dt.Year;
+ }
+
+ return eras;
+ }
+
+ // PAL Layer ends here
+
+ private static string[] JapaneseErasEnglishNames = new String[] { "M", "T", "S", "H" };
+
+ private static string GetJapaneseEnglishEraName(int era)
+ {
+ Debug.Assert(era > 0);
+ return era <= JapaneseErasEnglishNames.Length ? JapaneseErasEnglishNames[era - 1] : " ";
+ }
+
+ private static bool GetJapaneseEraInfo(int era, out DateTimeOffset dateOffset, out string eraName, out string abbreviatedEraName)
+ {
+ return WinRTInterop.Callbacks.GetJapaneseEraInfo(era, out dateOffset, out eraName, out abbreviatedEraName);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.cs b/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.cs
new file mode 100644
index 0000000000..4130801de5
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/JapaneseCalendar.cs
@@ -0,0 +1,413 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using Debug = BCLDebug;
+#endif
+
+ /*=================================JapaneseCalendar==========================
+ **
+ ** JapaneseCalendar is based on Gregorian calendar. The month and day values are the same as
+ ** Gregorian calendar. However, the year value is an offset to the Gregorian
+ ** year based on the era.
+ **
+ ** This system is adopted by Emperor Meiji in 1868. The year value is counted based on the reign of an emperor,
+ ** and the era begins on the day an emperor ascends the throne and continues until his death.
+ ** The era changes at 12:00AM.
+ **
+ ** For example, the current era is Heisei. It started on 1989/1/8 A.D. Therefore, Gregorian year 1989 is also Heisei 1st.
+ ** 1989/1/8 A.D. is also Heisei 1st 1/8.
+ **
+ ** Any date in the year during which era is changed can be reckoned in either era. For example,
+ ** 1989/1/1 can be 1/1 Heisei 1st year or 1/1 Showa 64th year.
+ **
+ ** Note:
+ ** The DateTime can be represented by the JapaneseCalendar are limited to two factors:
+ ** 1. The min value and max value of DateTime class.
+ ** 2. The available era information.
+ **
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1868/09/08 9999/12/31
+ ** Japanese Meiji 01/01 Heisei 8011/12/31
+ ============================================================================*/
+
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class JapaneseCalendar : Calendar
+ {
+ internal static readonly DateTime calendarMinValue = new DateTime(1868, 9, 8);
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (calendarMinValue);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+ //
+ // Using a field initializer rather than a static constructor so that the whole class can be lazy
+ // init.
+ internal static volatile EraInfo[] japaneseEraInfo;
+
+ //
+ // Read our era info
+ //
+ // m_EraInfo must be listed in reverse chronological order. The most recent era
+ // should be the first element.
+ // That is, m_EraInfo[0] contains the most recent era.
+ //
+ // We know about 4 built-in eras, however users may add additional era(s) from the
+ // registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras
+ // we don't read the registry and instead we call WinRT to get the needed informatio
+ //
+ // Registry values look like:
+ // yyyy.mm.dd=era_abbrev_english_englishabbrev
+ //
+ // Where yyyy.mm.dd is the registry value name, and also the date of the era start.
+ // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long)
+ // era is the Japanese Era name
+ // abbrev is the Abbreviated Japanese Era Name
+ // english is the English name for the Era (unused)
+ // englishabbrev is the Abbreviated English name for the era.
+ // . is a delimiter, but the value of . doesn't matter.
+ // '_' marks the space between the japanese era name, japanese abbreviated era name
+ // english name, and abbreviated english names.
+ //
+ internal static EraInfo[] GetEraInfo()
+ {
+ // See if we need to build it
+ if (japaneseEraInfo == null)
+ {
+ japaneseEraInfo = GetJapaneseEras();
+ // See if we have to use the built-in eras
+ if (japaneseEraInfo == null)
+ {
+ // We know about some built-in ranges
+ EraInfo[] defaultEraRanges = new EraInfo[4];
+ defaultEraRanges[0] = new EraInfo(4, 1989, 1, 8, 1988, 1, GregorianCalendar.MaxYear - 1988,
+ "\x5e73\x6210", "\x5e73", "H"); // era #4 start year/month/day, yearOffset, minEraYear
+ defaultEraRanges[1] = new EraInfo(3, 1926, 12, 25, 1925, 1, 1989 - 1925,
+ "\x662d\x548c", "\x662d", "S"); // era #3,start year/month/day, yearOffset, minEraYear
+ defaultEraRanges[2] = new EraInfo(2, 1912, 7, 30, 1911, 1, 1926 - 1911,
+ "\x5927\x6b63", "\x5927", "T"); // era #2,start year/month/day, yearOffset, minEraYear
+ defaultEraRanges[3] = new EraInfo(1, 1868, 1, 1, 1867, 1, 1912 - 1867,
+ "\x660e\x6cbb", "\x660e", "M"); // era #1,start year/month/day, yearOffset, minEraYear
+
+ // Remember the ranges we built
+ japaneseEraInfo = defaultEraRanges;
+ }
+ }
+
+ // return the era we found/made
+ return japaneseEraInfo;
+ }
+
+ internal static volatile Calendar s_defaultInstance;
+ internal GregorianCalendarHelper helper;
+
+ /*=================================GetDefaultInstance==========================
+ **Action: Internal method to provide a default intance of JapaneseCalendar. Used by NLS+ implementation
+ ** and other calendars.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+ internal static Calendar GetDefaultInstance()
+ {
+ if (s_defaultInstance == null)
+ {
+ s_defaultInstance = new JapaneseCalendar();
+ }
+ return (s_defaultInstance);
+ }
+
+
+ public JapaneseCalendar()
+ {
+ try
+ {
+ new CultureInfo("ja-JP");
+ }
+ catch (ArgumentException e)
+ {
+ throw new TypeInitializationException(this.GetType().ToString(), e);
+ }
+ helper = new GregorianCalendarHelper(this, GetEraInfo());
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return CalendarId.JAPAN;
+ }
+ }
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ return (helper.AddMonths(time, months));
+ }
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (helper.AddYears(time, years));
+ }
+
+ /*=================================GetDaysInMonth==========================
+ **Action: Returns the number of days in the month given by the year and month arguments.
+ **Returns: The number of days in the given month.
+ **Arguments:
+ ** year The year in Japanese calendar.
+ ** month The month
+ ** era The Japanese era value.
+ **Exceptions
+ ** ArgumentException If month is less than 1 or greater * than 12.
+ ============================================================================*/
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ return (helper.GetDaysInMonth(year, month, era));
+ }
+
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ return (helper.GetDaysInYear(year, era));
+ }
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (helper.GetDayOfMonth(time));
+ }
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return (helper.GetDayOfWeek(time));
+ }
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (helper.GetDayOfYear(time));
+ }
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ return (helper.GetMonthsInYear(year, era));
+ }
+
+
+ [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems.
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ return (helper.GetWeekOfYear(time, rule, firstDayOfWeek));
+ }
+
+ /*=================================GetEra==========================
+ **Action: Get the era value of the specified time.
+ **Returns: The era value for the specified time.
+ **Arguments:
+ ** time the specified date time.
+ **Exceptions: ArgumentOutOfRangeException if time is out of the valid era ranges.
+ ============================================================================*/
+
+
+ public override int GetEra(DateTime time)
+ {
+ return (helper.GetEra(time));
+ }
+
+
+ public override int GetMonth(DateTime time)
+ {
+ return (helper.GetMonth(time));
+ }
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (helper.GetYear(time));
+ }
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ return (helper.IsLeapDay(year, month, day, era));
+ }
+
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ return (helper.IsLeapYear(year, era));
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ return (helper.GetLeapMonth(year, era));
+ }
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ return (helper.IsLeapMonth(year, month, era));
+ }
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ return (helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era));
+ }
+
+ // For Japanese calendar, four digit year is not used. Few emperors will live for more than one hundred years.
+ // Therefore, for any two digit number, we just return the original number.
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year <= 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year > helper.MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ helper.MaxYear));
+ }
+ return (year);
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (helper.Eras);
+ }
+ }
+
+ //
+ // Return the various era strings
+ // Note: The arrays are backwards of the eras
+ //
+ internal static String[] EraNames()
+ {
+ EraInfo[] eras = GetEraInfo();
+ String[] eraNames = new String[eras.Length];
+
+ for (int i = 0; i < eras.Length; i++)
+ {
+ // Strings are in chronological order, eras are backwards order.
+ eraNames[i] = eras[eras.Length - i - 1].eraName;
+ }
+
+ return eraNames;
+ }
+
+ internal static String[] AbbrevEraNames()
+ {
+ EraInfo[] eras = GetEraInfo();
+ String[] erasAbbrev = new String[eras.Length];
+
+ for (int i = 0; i < eras.Length; i++)
+ {
+ // Strings are in chronological order, eras are backwards order.
+ erasAbbrev[i] = eras[eras.Length - i - 1].abbrevEraName;
+ }
+
+ return erasAbbrev;
+ }
+
+ internal static String[] EnglishEraNames()
+ {
+ EraInfo[] eras = GetEraInfo();
+ String[] erasEnglish = new String[eras.Length];
+
+ for (int i = 0; i < eras.Length; i++)
+ {
+ // Strings are in chronological order, eras are backwards order.
+ erasEnglish[i] = eras[eras.Length - i - 1].englishEraName;
+ }
+
+ return erasEnglish;
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 99;
+
+ internal override bool IsValidYear(int year, int era)
+ {
+ return helper.IsValidYear(year, era);
+ }
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > helper.MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ helper.MaxYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/JapaneseLunisolarCalendar.cs b/src/mscorlib/corefx/System/Globalization/JapaneseLunisolarCalendar.cs
new file mode 100644
index 0000000000..ecdaced2d7
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/JapaneseLunisolarCalendar.cs
@@ -0,0 +1,311 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about JapaneseLunisolarCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1960/01/28 2050/01/22
+ ** JapaneseLunisolar 1960/01/01 2049/12/29
+ */
+
+ [Serializable]
+ public class JapaneseLunisolarCalendar : EastAsianLunisolarCalendar
+ {
+ //
+ // The era value for the current era.
+ //
+
+ public const int JapaneseEra = 1;
+
+ internal GregorianCalendarHelper helper;
+
+ internal const int MIN_LUNISOLAR_YEAR = 1960;
+ internal const int MAX_LUNISOLAR_YEAR = 2049;
+
+ internal const int MIN_GREGORIAN_YEAR = 1960;
+ internal const int MIN_GREGORIAN_MONTH = 1;
+ internal const int MIN_GREGORIAN_DAY = 28;
+
+ internal const int MAX_GREGORIAN_YEAR = 2050;
+ internal const int MAX_GREGORIAN_MONTH = 1;
+ internal const int MAX_GREGORIAN_DAY = 22;
+
+ internal static DateTime minDate = new DateTime(MIN_GREGORIAN_YEAR, MIN_GREGORIAN_MONTH, MIN_GREGORIAN_DAY);
+ internal static DateTime maxDate = new DateTime((new DateTime(MAX_GREGORIAN_YEAR, MAX_GREGORIAN_MONTH, MAX_GREGORIAN_DAY, 23, 59, 59, 999)).Ticks + 9999);
+
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // 1959 from ChineseLunisolarCalendar
+ return 354;
+ }
+ }
+
+ private static readonly int[,] s_yinfo =
+ {
+ /*Y LM Lmon Lday DaysPerMonth D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 #Days
+ 1960 */
+ { 6 , 1 , 28 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1961 */{ 0 , 2 , 15 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1962 */{ 0 , 2 , 5 , 19808 },/* 29 30 29 29 30 30 29 30 29 30 30 29 0 354
+1963 */{ 4 , 1 , 25 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1964 */{ 0 , 2 , 13 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1965 */{ 0 , 2 , 2 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 0 354
+1966 */{ 3 , 1 , 22 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 29 383
+1967 */{ 0 , 2 , 9 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1968 */{ 7 , 1 , 30 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1969 */{ 0 , 2 , 17 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1970 */{ 0 , 2 , 6 , 39632 },/* 30 29 29 30 30 29 30 29 30 30 29 30 0 355
+1971 */{ 5 , 1 , 27 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1972 */{ 0 , 2 , 15 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1973 */{ 0 , 2 , 3 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+1974 */{ 4 , 1 , 23 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1975 */{ 0 , 2 , 11 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1976 */{ 8 , 1 , 31 , 54600 },/* 30 30 29 30 29 30 29 30 29 30 29 29 30 384
+1977 */{ 0 , 2 , 18 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1978 */{ 0 , 2 , 7 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 0 355
+1979 */{ 6 , 1 , 28 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1980 */{ 0 , 2 , 16 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1981 */{ 0 , 2 , 5 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1982 */{ 4 , 1 , 25 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1983 */{ 0 , 2 , 13 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1984 */{ 10 , 2 , 2 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1985 */{ 0 , 2 , 20 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1986 */{ 0 , 2 , 9 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1987 */{ 6 , 1 , 29 , 46504 },/* 30 29 30 30 29 30 29 30 30 29 30 29 30 385
+1988 */{ 0 , 2 , 18 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1989 */{ 0 , 2 , 6 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1990 */{ 5 , 1 , 27 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1991 */{ 0 , 2 , 15 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1992 */{ 0 , 2 , 4 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1993 */{ 3 , 1 , 23 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1994 */{ 0 , 2 , 10 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1995 */{ 8 , 1 , 31 , 27976 },/* 29 30 30 29 30 30 29 30 29 30 29 29 30 384
+1996 */{ 0 , 2 , 19 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1997 */{ 0 , 2 , 8 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1998 */{ 5 , 1 , 28 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1999 */{ 0 , 2 , 16 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2000 */{ 0 , 2 , 5 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2001 */{ 4 , 1 , 24 , 58536 },/* 30 30 30 29 29 30 29 29 30 29 30 29 30 384
+2002 */{ 0 , 2 , 12 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2003 */{ 0 , 2 , 1 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2004 */{ 2 , 1 , 22 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2005 */{ 0 , 2 , 9 , 22208 },/* 29 30 29 30 29 30 30 29 30 30 29 29 0 354
+2006 */{ 7 , 1 , 29 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+2007 */{ 0 , 2 , 18 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+2008 */{ 0 , 2 , 7 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+2009 */{ 5 , 1 , 26 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+2010 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2011 */{ 0 , 2 , 3 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2012 */{ 3 , 1 , 23 , 47696 },/* 30 29 30 30 30 29 30 29 29 30 29 30 29 384
+2013 */{ 0 , 2 , 10 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+2014 */{ 9 , 1 , 31 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2015 */{ 0 , 2 , 19 , 19360 },/* 29 30 29 29 30 29 30 30 30 29 30 29 0 354
+2016 */{ 0 , 2 , 8 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2017 */{ 5 , 1 , 28 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+2018 */{ 0 , 2 , 16 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2019 */{ 0 , 2 , 5 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2020 */{ 4 , 1 , 25 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+2021 */{ 0 , 2 , 12 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2022 */{ 0 , 2 , 1 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2023 */{ 2 , 1 , 22 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2024 */{ 0 , 2 , 10 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2025 */{ 6 , 1 , 29 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+2026 */{ 0 , 2 , 17 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+2027 */{ 0 , 2 , 7 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 0 354
+2028 */{ 5 , 1 , 27 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 29 383
+2029 */{ 0 , 2 , 13 , 55600 },/* 30 30 29 30 30 29 29 30 29 29 30 30 0 355
+2030 */{ 0 , 2 , 3 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+2031 */{ 3 , 1 , 23 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 29 384
+2032 */{ 0 , 2 , 11 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2033 */{ 11 , 1 , 31 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+2034 */{ 0 , 2 , 19 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+2035 */{ 0 , 2 , 8 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2036 */{ 6 , 1 , 28 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+2037 */{ 0 , 2 , 15 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+2038 */{ 0 , 2 , 4 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2039 */{ 5 , 1 , 24 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 29 384
+2040 */{ 0 , 2 , 12 , 46752 },/* 30 29 30 30 29 30 30 29 30 29 30 29 0 355
+2041 */{ 0 , 2 , 1 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2042 */{ 2 , 1 , 22 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+2043 */{ 0 , 2 , 10 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+2044 */{ 7 , 1 , 30 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+2045 */{ 0 , 2 , 17 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+2046 */{ 0 , 2 , 6 , 45648 },/* 30 29 30 30 29 29 30 29 29 30 29 30 0 354
+2047 */{ 5 , 1 , 26 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+2048 */{ 0 , 2 , 14 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+2049 */{ 0 , 2 , 2 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+ */ };
+
+ internal override int MinCalendarYear
+ {
+ get
+ {
+ return (MIN_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override int MaxCalendarYear
+ {
+ get
+ {
+ return (MAX_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override DateTime MinDate
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ internal override DateTime MaxDate
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ internal override EraInfo[] CalEraInfo
+ {
+ get
+ {
+ return (JapaneseCalendar.GetEraInfo());
+ }
+ }
+
+ internal override int GetYearInfo(int LunarYear, int Index)
+ {
+ if ((LunarYear < MIN_LUNISOLAR_YEAR) || (LunarYear > MAX_LUNISOLAR_YEAR))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MIN_LUNISOLAR_YEAR,
+ MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return s_yinfo[LunarYear - MIN_LUNISOLAR_YEAR, Index];
+ }
+
+ internal override int GetYear(int year, DateTime time)
+ {
+ return helper.GetYear(year, time);
+ }
+
+ internal override int GetGregorianYear(int year, int era)
+ {
+ return helper.GetGregorianYear(year, era);
+ }
+
+ // Trim off the eras that are before our date range
+ private static EraInfo[] TrimEras(EraInfo[] baseEras)
+ {
+ EraInfo[] newEras = new EraInfo[baseEras.Length];
+ int newIndex = 0;
+
+ // Eras have most recent first, so start with that
+ for (int i = 0; i < baseEras.Length; i++)
+ {
+ // If this one's minimum year is bigger than our maximum year
+ // then we can't use it.
+ if (baseEras[i].yearOffset + baseEras[i].minEraYear >= MAX_LUNISOLAR_YEAR)
+ {
+ // skip this one.
+ continue;
+ }
+
+ // If this one's maximum era is less than our minimum era
+ // then we've gotten too low in the era #s, so we're done
+ if (baseEras[i].yearOffset + baseEras[i].maxEraYear < MIN_LUNISOLAR_YEAR)
+ {
+ break;
+ }
+
+ // Wasn't too large or too small, can use this one
+ newEras[newIndex] = baseEras[i];
+ newIndex++;
+ }
+
+ // If we didn't copy any then something was wrong, just return base
+ if (newIndex == 0) return baseEras;
+
+ // Resize the output array
+ Array.Resize(ref newEras, newIndex);
+ return newEras;
+ }
+
+
+ // Construct an instance of JapaneseLunisolar calendar.
+ public JapaneseLunisolarCalendar()
+ {
+ helper = new GregorianCalendarHelper(this, TrimEras(JapaneseCalendar.GetEraInfo()));
+ }
+
+
+ public override int GetEra(DateTime time)
+ {
+ return (helper.GetEra(time));
+ }
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ return (CalendarId.JAPAN);
+ }
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.JAPANESELUNISOLAR);
+ }
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (helper.Eras);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/JulianCalendar.cs b/src/mscorlib/corefx/System/Globalization/JulianCalendar.cs
new file mode 100644
index 0000000000..6721899ac9
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/JulianCalendar.cs
@@ -0,0 +1,452 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ //
+ // This class implements the Julian calendar. In 48 B.C. Julius Caesar ordered a calendar reform, and this calendar
+ // is called Julian calendar. It consisted of a solar year of twelve months and of 365 days with an extra day
+ // every fourth year.
+ //*
+ //* Calendar support range:
+ //* Calendar Minimum Maximum
+ //* ========== ========== ==========
+ //* Gregorian 0001/01/01 9999/12/31
+ //* Julia 0001/01/03 9999/10/19
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public class JulianCalendar : Calendar
+ {
+ public static readonly int JulianEra = 1;
+
+ private const int DatePartYear = 0;
+ private const int DatePartDayOfYear = 1;
+ private const int DatePartMonth = 2;
+ private const int DatePartDay = 3;
+
+ // Number of days in a non-leap year
+ private const int JulianDaysPerYear = 365;
+ // Number of days in 4 years
+ private const int JulianDaysPer4Years = JulianDaysPerYear * 4 + 1;
+
+ private static readonly int[] s_daysToMonth365 =
+ {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+ };
+
+ private static readonly int[] s_daysToMonth366 =
+ {
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
+ };
+
+ // Gregorian Calendar 9999/12/31 = Julian Calendar 9999/10/19
+ // keep it as variable field for serialization compat.
+ internal int MaxYear = 9999;
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MinValue);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+ // Return the type of the Julian calendar.
+ //
+
+ //[System.Runtime.InteropServices.ComVisible(false)]
+ //public override CalendarAlgorithmType AlgorithmType
+ //{
+ // get
+ // {
+ // return CalendarAlgorithmType.SolarCalendar;
+ // }
+ //}
+
+ public JulianCalendar()
+ {
+ // There is no system setting of TwoDigitYear max, so set the value here.
+ twoDigitYearMax = 2029;
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return CalendarId.JULIAN;
+ }
+ }
+
+ internal static void CheckEraRange(int era)
+ {
+ if (era != CurrentEra && era != JulianEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ }
+
+ internal void CheckYearEraRange(int year, int era)
+ {
+ CheckEraRange(era);
+ if (year <= 0 || year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxYear));
+ }
+ }
+
+ internal static void CheckMonthRange(int month)
+ {
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ }
+
+ /*===================================CheckDayRange============================
+ **Action: Check for if the day value is valid.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ **Notes:
+ ** Before calling this method, call CheckYearEraRange()/CheckMonthRange() to make
+ ** sure year/month values are correct.
+ ============================================================================*/
+
+ internal static void CheckDayRange(int year, int month, int day)
+ {
+ if (year == 1 && month == 1)
+ {
+ // The mimimum supported Julia date is Julian 0001/01/03.
+ if (day < 3)
+ {
+ throw new ArgumentOutOfRangeException(null,
+ SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+ }
+ bool isLeapYear = (year % 4) == 0;
+ int[] days = isLeapYear ? s_daysToMonth366 : s_daysToMonth365;
+ int monthDays = days[month] - days[month - 1];
+ if (day < 1 || day > monthDays)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ monthDays));
+ }
+ }
+
+
+ // Returns a given date part of this DateTime. This method is used
+ // to compute the year, day-of-year, month, or day part.
+ internal static int GetDatePart(long ticks, int part)
+ {
+ // Gregorian 1/1/0001 is Julian 1/3/0001. Remember DateTime(0) is refered to Gregorian 1/1/0001.
+ // The following line convert Gregorian ticks to Julian ticks.
+ long julianTicks = ticks + TicksPerDay * 2;
+ // n = number of days since 1/1/0001
+ int n = (int)(julianTicks / TicksPerDay);
+ // y4 = number of whole 4-year periods within 100-year period
+ int y4 = n / JulianDaysPer4Years;
+ // n = day number within 4-year period
+ n -= y4 * JulianDaysPer4Years;
+ // y1 = number of whole years within 4-year period
+ int y1 = n / JulianDaysPerYear;
+ // Last year has an extra day, so decrement result if 4
+ if (y1 == 4) y1 = 3;
+ // If year was requested, compute and return it
+ if (part == DatePartYear)
+ {
+ return (y4 * 4 + y1 + 1);
+ }
+ // n = day number within year
+ n -= y1 * JulianDaysPerYear;
+ // If day-of-year was requested, return it
+ if (part == DatePartDayOfYear)
+ {
+ return (n + 1);
+ }
+ // Leap year calculation looks different from IsLeapYear since y1, y4,
+ // and y100 are relative to year 1, not year 0
+ bool leapYear = (y1 == 3);
+ int[] days = leapYear ? s_daysToMonth366 : s_daysToMonth365;
+ // All months have less than 32 days, so n >> 5 is a good conservative
+ // estimate for the month
+ int m = n >> 5 + 1;
+ // m = 1-based month number
+ while (n >= days[m]) m++;
+ // If month was requested, return it
+ if (part == DatePartMonth) return (m);
+ // Return 1-based day-of-month
+ return (n - days[m - 1] + 1);
+ }
+
+ // Returns the tick count corresponding to the given year, month, and day.
+ internal static long DateToTicks(int year, int month, int day)
+ {
+ int[] days = (year % 4 == 0) ? s_daysToMonth366 : s_daysToMonth365;
+ int y = year - 1;
+ int n = y * 365 + y / 4 + days[month - 1] + day - 1;
+ // Gregorian 1/1/0001 is Julian 1/3/0001. n * TicksPerDay is the ticks in JulianCalendar.
+ // Therefore, we subtract two days in the following to convert the ticks in JulianCalendar
+ // to ticks in Gregorian calendar.
+ return ((n - 2) * TicksPerDay);
+ }
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ -120000,
+ 120000));
+ }
+ Contract.EndContractBlock();
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+ int i = m - 1 + months;
+ if (i >= 0)
+ {
+ m = i % 12 + 1;
+ y = y + i / 12;
+ }
+ else
+ {
+ m = 12 + (i + 1) % 12;
+ y = y + (i - 11) / 12;
+ }
+ int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? s_daysToMonth366 : s_daysToMonth365;
+ int days = (daysArray[m] - daysArray[m - 1]);
+
+ if (d > days)
+ {
+ d = days;
+ }
+ long ticks = DateToTicks(y, m, d) + time.Ticks % TicksPerDay;
+ Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (AddMonths(time, years * 12));
+ }
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDay));
+ }
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDayOfYear));
+ }
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ CheckYearEraRange(year, era);
+ CheckMonthRange(month);
+ int[] days = (year % 4 == 0) ? s_daysToMonth366 : s_daysToMonth365;
+ return (days[month] - days[month - 1]);
+ }
+
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ // Year/Era range is done in IsLeapYear().
+ return (IsLeapYear(year, era) ? 366 : 365);
+ }
+
+
+ public override int GetEra(DateTime time)
+ {
+ return (JulianEra);
+ }
+
+
+ public override int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartMonth));
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { JulianEra });
+ }
+ }
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ CheckYearEraRange(year, era);
+ return (12);
+ }
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartYear));
+ }
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ CheckMonthRange(month);
+ // Year/Era range check is done in IsLeapYear().
+ if (IsLeapYear(year, era))
+ {
+ CheckDayRange(year, month, day);
+ return (month == 2 && day == 29);
+ }
+ CheckDayRange(year, month, day);
+ return (false);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ CheckYearEraRange(year, era);
+ return (0);
+ }
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ CheckYearEraRange(year, era);
+ CheckMonthRange(month);
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ CheckYearEraRange(year, era);
+ return (year % 4 == 0);
+ }
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ CheckYearEraRange(year, era);
+ CheckMonthRange(month);
+ CheckDayRange(year, month, day);
+ if (millisecond < 0 || millisecond >= MillisPerSecond)
+ {
+ throw new ArgumentOutOfRangeException(
+ "millisecond",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ MillisPerSecond - 1));
+ }
+
+ if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60)
+ {
+ return new DateTime(DateToTicks(year, month, day) + (new TimeSpan(0, hour, minute, second, millisecond)).Ticks);
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+ }
+ }
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ MaxYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year > MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Bounds_Lower_Upper,
+ 1,
+ MaxYear));
+ }
+ return (base.ToFourDigitYear(year));
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/KoreanCalendar.cs b/src/mscorlib/corefx/System/Globalization/KoreanCalendar.cs
new file mode 100644
index 0000000000..38a0b41fda
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/KoreanCalendar.cs
@@ -0,0 +1,264 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ /*=================================KoreanCalendar==========================
+ **
+ ** Korean calendar is based on the Gregorian calendar. And the year is an offset to Gregorian calendar.
+ ** That is,
+ ** Korean year = Gregorian year + 2333. So 2000/01/01 A.D. is Korean 4333/01/01
+ **
+ ** 0001/1/1 A.D. is Korean year 2334.
+ **
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 0001/01/01 9999/12/31
+ ** Korean 2334/01/01 12332/12/31
+ ============================================================================*/
+
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public class KoreanCalendar : Calendar
+ {
+ //
+ // The era value for the current era.
+ //
+
+ public const int KoreanEra = 1;
+
+ // Since
+ // Gregorian Year = Era Year + yearOffset
+ // Gregorian Year 1 is Korean year 2334, so that
+ // 1 = 2334 + yearOffset
+ // So yearOffset = -2333
+ // Gregorian year 2001 is Korean year 4334.
+
+ //m_EraInfo[0] = new EraInfo(1, new DateTime(1, 1, 1).Ticks, -2333, 2334, GregorianCalendar.MaxYear + 2333);
+
+ // Initialize our era info.
+ internal static EraInfo[] koreanEraInfo = new EraInfo[] {
+ new EraInfo( 1, 1, 1, 1, -2333, 2334, GregorianCalendar.MaxYear + 2333) // era #, start year/month/day, yearOffset, minEraYear
+ };
+
+ internal GregorianCalendarHelper helper;
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MinValue);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+ public KoreanCalendar()
+ {
+ try
+ {
+ new CultureInfo("ko-KR");
+ }
+ catch (ArgumentException e)
+ {
+ throw new TypeInitializationException(this.GetType().ToString(), e);
+ }
+ helper = new GregorianCalendarHelper(this, koreanEraInfo);
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return CalendarId.KOREA;
+ }
+ }
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ return (helper.AddMonths(time, months));
+ }
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (helper.AddYears(time, years));
+ }
+
+ /*=================================GetDaysInMonth==========================
+ **Action: Returns the number of days in the month given by the year and month arguments.
+ **Returns: The number of days in the given month.
+ **Arguments:
+ ** year The year in Korean calendar.
+ ** month The month
+ ** era The Japanese era value.
+ **Exceptions
+ ** ArgumentException If month is less than 1 or greater * than 12.
+ ============================================================================*/
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ return (helper.GetDaysInMonth(year, month, era));
+ }
+
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ return (helper.GetDaysInYear(year, era));
+ }
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (helper.GetDayOfMonth(time));
+ }
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return (helper.GetDayOfWeek(time));
+ }
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (helper.GetDayOfYear(time));
+ }
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ return (helper.GetMonthsInYear(year, era));
+ }
+
+
+ [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems.
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ return (helper.GetWeekOfYear(time, rule, firstDayOfWeek));
+ }
+
+
+ public override int GetEra(DateTime time)
+ {
+ return (helper.GetEra(time));
+ }
+
+ public override int GetMonth(DateTime time)
+ {
+ return (helper.GetMonth(time));
+ }
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (helper.GetYear(time));
+ }
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ return (helper.IsLeapDay(year, month, day, era));
+ }
+
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ return (helper.IsLeapYear(year, era));
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ return (helper.GetLeapMonth(year, era));
+ }
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ return (helper.IsLeapMonth(year, month, era));
+ }
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ return (helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era));
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (helper.Eras);
+ }
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 4362;
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > helper.MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ helper.MaxYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ return (helper.ToFourDigitYear(year, this.TwoDigitYearMax));
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/KoreanLunisolarCalendar.cs b/src/mscorlib/corefx/System/Globalization/KoreanLunisolarCalendar.cs
new file mode 100644
index 0000000000..68c4fab58f
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/KoreanLunisolarCalendar.cs
@@ -0,0 +1,1329 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about KoreanLunisolarCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 918/02/14 2051/02/10
+ ** KoreanLunisolar 918/01/01 2050/13/29
+ */
+
+ [Serializable]
+ public class KoreanLunisolarCalendar : EastAsianLunisolarCalendar
+ {
+ //
+ // The era value for the current era.
+ //
+
+ public const int GregorianEra = 1;
+
+ internal const int MIN_LUNISOLAR_YEAR = 918;
+ internal const int MAX_LUNISOLAR_YEAR = 2050;
+
+ internal const int MIN_GREGORIAN_YEAR = 918;
+ internal const int MIN_GREGORIAN_MONTH = 2;
+ internal const int MIN_GREGORIAN_DAY = 14;
+
+ internal const int MAX_GREGORIAN_YEAR = 2051;
+ internal const int MAX_GREGORIAN_MONTH = 2;
+ internal const int MAX_GREGORIAN_DAY = 10;
+
+ internal static DateTime minDate = new DateTime(MIN_GREGORIAN_YEAR, MIN_GREGORIAN_MONTH, MIN_GREGORIAN_DAY);
+ internal static DateTime maxDate = new DateTime((new DateTime(MAX_GREGORIAN_YEAR, MAX_GREGORIAN_MONTH, MAX_GREGORIAN_DAY, 23, 59, 59, 999)).Ticks + 9999);
+
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+
+
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // 917 -- From http://emr.cs.iit.edu/home/reingold/calendar-book/Calendrica.html
+ // using ChineseLunisolar
+ return 384;
+ }
+ }
+
+ private static readonly int[,] s_yinfo =
+ {
+ /*Y LM Lmon Lday DaysPerMonth D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 #Days
+ 918 */
+ { 0 , 2 , 14 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+919 */{ 0 , 2 , 4 , 17872 },/* 29 30 29 29 29 30 29 30 30 30 29 30 0 354
+920 */{ 6 , 1 , 24 , 41688 },/* 30 29 30 29 29 29 30 29 30 30 29 30 30 384
+921 */{ 0 , 2 , 11 , 41648 },/* 30 29 30 29 29 29 30 29 30 29 30 30 0 354
+922 */{ 0 , 1 , 31 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+923 */{ 4 , 1 , 20 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+924 */{ 0 , 2 , 8 , 27936 },/* 29 30 30 29 30 30 29 30 29 29 30 29 0 354
+925 */{ 12 , 1 , 27 , 44384 },/* 30 29 30 29 30 30 29 30 29 30 30 29 29 384
+926 */{ 0 , 2 , 15 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+927 */{ 0 , 2 , 5 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+928 */{ 8 , 1 , 26 , 17848 },/* 29 30 29 29 29 30 29 30 30 29 30 30 30 384
+929 */{ 0 , 2 , 13 , 17776 },/* 29 30 29 29 29 30 29 30 29 30 30 30 0 354
+930 */{ 0 , 2 , 2 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+931 */{ 5 , 1 , 22 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 29 383
+932 */{ 0 , 2 , 9 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+933 */{ 0 , 1 , 29 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+934 */{ 1 , 1 , 18 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+935 */{ 0 , 2 , 6 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+936 */{ 11 , 1 , 27 , 21344 },/* 29 30 29 30 29 29 30 30 29 30 30 29 29 383
+937 */{ 0 , 2 , 13 , 51904 },/* 30 30 29 29 30 29 30 29 30 30 29 29 0 354
+938 */{ 0 , 2 , 2 , 58720 },/* 30 30 30 29 29 30 29 30 29 30 30 29 0 355
+939 */{ 7 , 1 , 23 , 53928 },/* 30 30 29 30 29 29 30 29 30 29 30 29 30 384
+940 */{ 0 , 2 , 11 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+941 */{ 0 , 1 , 30 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+942 */{ 3 , 1 , 20 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+943 */{ 0 , 2 , 8 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+944 */{ 12 , 1 , 28 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 29 384
+945 */{ 0 , 2 , 15 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+946 */{ 0 , 2 , 5 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+947 */{ 7 , 1 , 25 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+948 */{ 0 , 2 , 13 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+949 */{ 0 , 2 , 1 , 45664 },/* 30 29 30 30 29 29 30 29 29 30 30 29 0 354
+950 */{ 5 , 1 , 21 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+951 */{ 0 , 2 , 9 , 45936 },/* 30 29 30 30 29 30 29 30 29 30 29 0 0 325
+952 */{ 0 , 12 , 31 , 43728 },/* 30 29 30 29 30 29 30 29 30 30 29 30 29 384
+953 */{ 1 , 1 , 18 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 29 384
+954 */{ 0 , 2 , 6 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+955 */{ 9 , 1 , 27 , 19128 },/* 29 30 29 29 30 29 30 29 30 29 30 30 30 384
+956 */{ 0 , 2 , 15 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+957 */{ 0 , 2 , 3 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+958 */{ 7 , 1 , 23 , 43672 },/* 30 29 30 29 30 29 30 29 30 29 29 30 30 384
+959 */{ 0 , 2 , 11 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+960 */{ 0 , 1 , 31 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+961 */{ 3 , 1 , 20 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+962 */{ 0 , 2 , 8 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+963 */{ 12 , 1 , 28 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 29 384
+964 */{ 0 , 2 , 16 , 41840 },/* 30 29 30 29 29 29 30 30 29 30 30 30 0 355
+965 */{ 0 , 2 , 5 , 20848 },/* 29 30 29 30 29 29 29 30 29 30 30 30 0 354
+966 */{ 8 , 1 , 25 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+967 */{ 0 , 2 , 12 , 54448 },/* 30 30 29 30 29 30 29 29 30 29 30 30 0 355
+968 */{ 0 , 2 , 2 , 23184 },/* 29 30 29 30 30 29 30 29 30 29 29 30 0 354
+969 */{ 5 , 1 , 21 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+970 */{ 0 , 2 , 9 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+971 */{ 0 , 1 , 30 , 10976 },/* 29 29 30 29 30 29 30 29 30 30 30 29 0 354
+972 */{ 2 , 1 , 19 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+973 */{ 0 , 2 , 6 , 41696 },/* 30 29 30 29 29 29 30 29 30 30 30 29 0 354
+974 */{ 10 , 1 , 26 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+975 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+976 */{ 0 , 2 , 3 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+977 */{ 7 , 1 , 22 , 55952 },/* 30 30 29 30 30 29 30 29 30 29 29 30 29 384
+978 */{ 0 , 2 , 10 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+979 */{ 0 , 1 , 31 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+980 */{ 3 , 1 , 21 , 10968 },/* 29 29 30 29 30 29 30 29 30 30 29 30 30 384
+981 */{ 0 , 2 , 8 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+982 */{ 12 , 1 , 28 , 37592 },/* 30 29 29 30 29 29 30 29 30 30 29 30 30 384
+983 */{ 0 , 2 , 16 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+984 */{ 0 , 2 , 5 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+985 */{ 9 , 1 , 24 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+986 */{ 0 , 2 , 12 , 44192 },/* 30 29 30 29 30 30 29 29 30 29 30 29 0 354
+987 */{ 0 , 2 , 1 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+988 */{ 5 , 1 , 22 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+989 */{ 0 , 2 , 9 , 19376 },/* 29 30 29 29 30 29 30 30 30 29 30 30 0 355
+990 */{ 0 , 1 , 30 , 9648 },/* 29 29 30 29 29 30 29 30 30 29 30 30 0 354
+991 */{ 2 , 1 , 19 , 37560 },/* 30 29 29 30 29 29 30 29 30 29 30 30 30 384
+992 */{ 0 , 2 , 7 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+993 */{ 10 , 1 , 26 , 26968 },/* 29 30 30 29 30 29 29 30 29 30 29 30 30 384
+994 */{ 0 , 2 , 14 , 22864 },/* 29 30 29 30 30 29 29 30 29 30 29 30 0 354
+995 */{ 0 , 2 , 3 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+996 */{ 7 , 1 , 23 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 29 384
+997 */{ 0 , 2 , 10 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+998 */{ 0 , 1 , 31 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+999 */{ 3 , 1 , 20 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1000 */{ 0 , 2 , 8 , 9584 },/* 29 29 30 29 29 30 29 30 29 30 30 30 0 354
+1001 */{ 12 , 1 , 28 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 29 383
+1002 */{ 0 , 2 , 15 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+1003 */{ 0 , 2 , 4 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1004 */{ 9 , 1 , 25 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1005 */{ 0 , 2 , 12 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1006 */{ 0 , 2 , 1 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1007 */{ 5 , 1 , 22 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1008 */{ 0 , 2 , 10 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+1009 */{ 0 , 1 , 29 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1010 */{ 2 , 1 , 18 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1011 */{ 0 , 2 , 6 , 45664 },/* 30 29 30 30 29 29 30 29 29 30 30 29 0 354
+1012 */{ 10 , 1 , 26 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1013 */{ 0 , 2 , 13 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1014 */{ 0 , 2 , 3 , 13728 },/* 29 29 30 30 29 30 29 30 30 29 30 29 0 354
+1015 */{ 6 , 1 , 23 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 29 384
+1016 */{ 0 , 2 , 11 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1017 */{ 0 , 1 , 31 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1018 */{ 4 , 1 , 20 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1019 */{ 0 , 2 , 8 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1020 */{ 12 , 1 , 28 , 43608 },/* 30 29 30 29 30 29 30 29 29 30 29 30 30 384
+1021 */{ 0 , 2 , 15 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1022 */{ 0 , 2 , 4 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1023 */{ 9 , 1 , 25 , 11688 },/* 29 29 30 29 30 30 29 30 30 29 30 29 30 384
+1024 */{ 0 , 2 , 13 , 11088 },/* 29 29 30 29 30 29 30 30 29 30 29 30 0 354
+1025 */{ 0 , 2 , 1 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1026 */{ 5 , 1 , 22 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 29 383
+1027 */{ 0 , 2 , 9 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 0 355
+1028 */{ 0 , 1 , 30 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1029 */{ 2 , 1 , 18 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1030 */{ 0 , 2 , 5 , 55952 },/* 30 30 29 30 30 29 30 29 30 29 29 30 0 355
+1031 */{ 10 , 1 , 26 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+1032 */{ 0 , 2 , 14 , 26320 },/* 29 30 30 29 29 30 30 29 30 30 29 30 0 355
+1033 */{ 0 , 2 , 3 , 9952 },/* 29 29 30 29 29 30 30 29 30 30 30 29 0 354
+1034 */{ 6 , 1 , 23 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1035 */{ 0 , 2 , 11 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1036 */{ 0 , 1 , 31 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1037 */{ 4 , 1 , 19 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1038 */{ 0 , 2 , 7 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1039 */{ 12 , 1 , 27 , 54928 },/* 30 30 29 30 29 30 30 29 30 29 29 30 29 384
+1040 */{ 0 , 2 , 15 , 46464 },/* 30 29 30 30 29 30 29 30 30 29 29 29 0 354
+1041 */{ 0 , 2 , 3 , 54960 },/* 30 30 29 30 29 30 30 29 30 29 30 30 0 356
+1042 */{ 9 , 1 , 25 , 9944 },/* 29 29 30 29 29 30 30 29 30 30 29 30 30 384
+1043 */{ 0 , 2 , 13 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1044 */{ 0 , 2 , 2 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+1045 */{ 5 , 1 , 21 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1046 */{ 0 , 2 , 9 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1047 */{ 0 , 1 , 29 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1048 */{ 1 , 1 , 18 , 46424 },/* 30 29 30 30 29 30 29 30 29 30 29 30 30 385
+1049 */{ 0 , 2 , 6 , 11600 },/* 29 29 30 29 30 30 29 30 29 30 29 30 0 354
+1050 */{ 11 , 1 , 26 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+1051 */{ 0 , 2 , 14 , 19376 },/* 29 30 29 29 30 29 30 30 30 29 30 30 0 355
+1052 */{ 0 , 2 , 4 , 9648 },/* 29 29 30 29 29 30 29 30 30 29 30 30 0 354
+1053 */{ 7 , 1 , 23 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1054 */{ 0 , 2 , 11 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1055 */{ 0 , 1 , 31 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1056 */{ 3 , 1 , 20 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1057 */{ 0 , 2 , 7 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1058 */{ 12 , 1 , 27 , 43864 },/* 30 29 30 29 30 29 30 30 29 30 29 30 30 385
+1059 */{ 0 , 2 , 16 , 10064 },/* 29 29 30 29 29 30 30 30 29 30 29 30 0 354
+1060 */{ 0 , 2 , 5 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1061 */{ 8 , 1 , 24 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1062 */{ 0 , 2 , 12 , 42336 },/* 30 29 30 29 29 30 29 30 29 30 30 29 0 354
+1063 */{ 0 , 2 , 1 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1064 */{ 5 , 1 , 21 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1065 */{ 0 , 2 , 8 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1066 */{ 0 , 1 , 29 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1067 */{ 1 , 1 , 18 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 29 384
+1068 */{ 0 , 2 , 6 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1069 */{ 11 , 1 , 26 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1070 */{ 0 , 2 , 14 , 18896 },/* 29 30 29 29 30 29 29 30 30 30 29 30 0 354
+1071 */{ 0 , 2 , 3 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1072 */{ 7 , 1 , 23 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1073 */{ 0 , 2 , 10 , 43616 },/* 30 29 30 29 30 29 30 29 29 30 30 29 0 354
+1074 */{ 0 , 1 , 30 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1075 */{ 4 , 1 , 20 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1076 */{ 0 , 2 , 8 , 13728 },/* 29 29 30 30 29 30 29 30 30 29 30 29 0 354
+1077 */{ 0 , 1 , 27 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1078 */{ 1 , 1 , 17 , 19352 },/* 29 30 29 29 30 29 30 30 30 29 29 30 30 384
+1079 */{ 0 , 2 , 5 , 17840 },/* 29 30 29 29 29 30 29 30 30 29 30 30 0 354
+1080 */{ 9 , 1 , 25 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1081 */{ 0 , 2 , 12 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1082 */{ 0 , 2 , 1 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1083 */{ 6 , 1 , 21 , 46408 },/* 30 29 30 30 29 30 29 30 29 30 29 29 30 384
+1084 */{ 0 , 2 , 9 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 0 355
+1085 */{ 0 , 1 , 29 , 11680 },/* 29 29 30 29 30 30 29 30 30 29 30 29 0 354
+1086 */{ 2 , 1 , 18 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 29 384
+1087 */{ 0 , 2 , 6 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1088 */{ 12 , 1 , 27 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 29 383
+1089 */{ 0 , 2 , 13 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 0 355
+1090 */{ 0 , 2 , 3 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1091 */{ 8 , 1 , 23 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1092 */{ 0 , 2 , 10 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+1093 */{ 0 , 1 , 30 , 23360 },/* 29 30 29 30 30 29 30 30 29 30 29 29 0 354
+1094 */{ 4 , 1 , 19 , 43880 },/* 30 29 30 29 30 29 30 30 29 30 30 29 30 385
+1095 */{ 0 , 2 , 8 , 10976 },/* 29 29 30 29 30 29 30 29 30 30 30 29 0 354
+1096 */{ 0 , 1 , 28 , 58896 },/* 30 30 30 29 29 30 30 29 29 29 29 30 0 354
+1097 */{ 2 , 1 , 16 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 29 384
+1098 */{ 0 , 2 , 4 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1099 */{ 9 , 1 , 24 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1100 */{ 0 , 2 , 12 , 21664 },/* 29 30 29 30 29 30 29 29 30 29 30 29 0 353
+1101 */{ 0 , 1 , 31 , 54864 },/* 30 30 29 30 29 30 30 29 29 30 29 30 0 355
+1102 */{ 6 , 1 , 21 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1103 */{ 0 , 2 , 9 , 21968 },/* 29 30 29 30 29 30 29 30 30 30 29 30 0 355
+1104 */{ 0 , 1 , 30 , 9936 },/* 29 29 30 29 29 30 30 29 30 30 29 30 0 354
+1105 */{ 2 , 1 , 18 , 37608 },/* 30 29 29 30 29 29 30 29 30 30 30 29 30 384
+1106 */{ 0 , 2 , 6 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+1107 */{ 10 , 1 , 26 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1108 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1109 */{ 0 , 2 , 2 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1110 */{ 8 , 1 , 22 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1111 */{ 0 , 2 , 10 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1112 */{ 0 , 1 , 31 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1113 */{ 4 , 1 , 20 , 9656 },/* 29 29 30 29 29 30 29 30 30 29 30 30 30 384
+1114 */{ 0 , 2 , 8 , 17776 },/* 29 30 29 29 29 30 29 30 29 30 30 30 0 354
+1115 */{ 0 , 1 , 28 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1116 */{ 1 , 1 , 17 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1117 */{ 0 , 2 , 4 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1118 */{ 9 , 1 , 24 , 29352 },/* 29 30 30 30 29 29 30 29 30 29 30 29 30 384
+1119 */{ 0 , 2 , 12 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1120 */{ 0 , 2 , 1 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1121 */{ 5 , 1 , 21 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1122 */{ 0 , 2 , 9 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1123 */{ 0 , 1 , 29 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1124 */{ 3 , 1 , 19 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 29 383
+1125 */{ 0 , 2 , 5 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1126 */{ 11 , 1 , 25 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1127 */{ 0 , 2 , 13 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1128 */{ 0 , 2 , 3 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1129 */{ 8 , 1 , 22 , 39824 },/* 30 29 29 30 30 29 30 30 30 29 29 30 29 384
+1130 */{ 0 , 2 , 10 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1131 */{ 0 , 1 , 31 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1132 */{ 4 , 1 , 20 , 42216 },/* 30 29 30 29 29 30 29 29 30 30 30 29 30 384
+1133 */{ 0 , 2 , 7 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1134 */{ 0 , 1 , 27 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1135 */{ 2 , 1 , 16 , 55592 },/* 30 30 29 30 30 29 29 30 29 29 30 29 30 384
+1136 */{ 0 , 2 , 4 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1137 */{ 10 , 1 , 23 , 54952 },/* 30 30 29 30 29 30 30 29 30 29 30 29 30 385
+1138 */{ 0 , 2 , 12 , 11680 },/* 29 29 30 29 30 30 29 30 30 29 30 29 0 354
+1139 */{ 0 , 2 , 1 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1140 */{ 6 , 1 , 22 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+1141 */{ 0 , 2 , 9 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1142 */{ 0 , 1 , 29 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1143 */{ 4 , 1 , 18 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1144 */{ 0 , 2 , 6 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1145 */{ 11 , 1 , 25 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+1146 */{ 0 , 2 , 13 , 27456 },/* 29 30 30 29 30 29 30 30 29 30 29 29 0 354
+1147 */{ 0 , 2 , 2 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1148 */{ 8 , 1 , 23 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 29 384
+1149 */{ 0 , 2 , 10 , 39280 },/* 30 29 29 30 30 29 29 30 29 30 30 30 0 355
+1150 */{ 0 , 1 , 31 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1151 */{ 4 , 1 , 20 , 25784 },/* 29 30 30 29 29 30 29 29 30 29 30 30 30 384
+1152 */{ 0 , 2 , 8 , 21680 },/* 29 30 29 30 29 30 29 29 30 29 30 30 0 354
+1153 */{ 12 , 1 , 27 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1154 */{ 0 , 2 , 14 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+1155 */{ 0 , 2 , 4 , 23232 },/* 29 30 29 30 30 29 30 29 30 30 29 29 0 354
+1156 */{ 10 , 1 , 24 , 43880 },/* 30 29 30 29 30 29 30 30 29 30 30 29 30 385
+1157 */{ 0 , 2 , 12 , 9952 },/* 29 29 30 29 29 30 30 29 30 30 30 29 0 354
+1158 */{ 0 , 2 , 1 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1159 */{ 6 , 1 , 21 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 29 384
+1160 */{ 0 , 2 , 9 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1161 */{ 0 , 1 , 28 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1162 */{ 2 , 1 , 17 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1163 */{ 0 , 2 , 5 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1164 */{ 11 , 1 , 26 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1165 */{ 0 , 2 , 13 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1166 */{ 0 , 2 , 3 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1167 */{ 7 , 1 , 23 , 37608 },/* 30 29 29 30 29 29 30 29 30 30 30 29 30 384
+1168 */{ 0 , 2 , 11 , 37488 },/* 30 29 29 30 29 29 30 29 29 30 30 30 0 354
+1169 */{ 0 , 1 , 30 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1170 */{ 5 , 1 , 19 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1171 */{ 0 , 2 , 7 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1172 */{ 0 , 1 , 27 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1173 */{ 1 , 1 , 16 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1174 */{ 0 , 2 , 4 , 19888 },/* 29 30 29 29 30 30 29 30 30 29 30 30 0 355
+1175 */{ 9 , 1 , 25 , 9648 },/* 29 29 30 29 29 30 29 30 30 29 30 30 29 383
+1176 */{ 0 , 2 , 12 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1177 */{ 0 , 2 , 1 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1178 */{ 6 , 1 , 21 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1179 */{ 0 , 2 , 9 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1180 */{ 0 , 1 , 29 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1181 */{ 3 , 1 , 17 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1182 */{ 0 , 2 , 5 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1183 */{ 11 , 1 , 26 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1184 */{ 0 , 2 , 14 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1185 */{ 0 , 2 , 2 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1186 */{ 7 , 1 , 23 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 29 383
+1187 */{ 0 , 2 , 10 , 53392 },/* 30 30 29 30 29 29 30 29 29 30 30 0 0 325
+1188 */{ 0 , 1 , 1 , 29848 },/* 29 30 30 30 29 30 29 29 30 29 29 30 30 384
+1189 */{ 5 , 1 , 19 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1190 */{ 0 , 2 , 7 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1191 */{ 0 , 1 , 27 , 39760 },/* 30 29 29 30 30 29 30 30 29 30 29 30 0 355
+1192 */{ 2 , 1 , 17 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1193 */{ 0 , 2 , 4 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1194 */{ 10 , 1 , 24 , 42216 },/* 30 29 30 29 29 30 29 29 30 30 30 29 30 384
+1195 */{ 0 , 2 , 12 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1196 */{ 0 , 2 , 1 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1197 */{ 6 , 1 , 20 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1198 */{ 0 , 2 , 8 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1199 */{ 0 , 1 , 28 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 0 355
+1200 */{ 2 , 1 , 18 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 29 384
+1201 */{ 0 , 2 , 5 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1202 */{ 12 , 1 , 26 , 18904 },/* 29 30 29 29 30 29 29 30 30 30 29 30 30 384
+1203 */{ 0 , 2 , 14 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1204 */{ 0 , 2 , 3 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1205 */{ 8 , 1 , 22 , 43608 },/* 30 29 30 29 30 29 30 29 29 30 29 30 30 384
+1206 */{ 0 , 2 , 10 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1207 */{ 0 , 1 , 30 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1208 */{ 4 , 1 , 19 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 29 384
+1209 */{ 0 , 2 , 6 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1210 */{ 0 , 1 , 27 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1211 */{ 2 , 1 , 17 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1212 */{ 0 , 2 , 5 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1213 */{ 9 , 1 , 24 , 25784 },/* 29 30 30 29 29 30 29 29 30 29 30 30 30 384
+1214 */{ 0 , 2 , 12 , 21680 },/* 29 30 29 30 29 30 29 29 30 29 30 30 0 354
+1215 */{ 0 , 2 , 1 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1216 */{ 7 , 1 , 21 , 27944 },/* 29 30 30 29 30 30 29 30 29 29 30 29 30 384
+1217 */{ 0 , 2 , 8 , 23232 },/* 29 30 29 30 30 29 30 29 30 30 29 29 0 354
+1218 */{ 0 , 1 , 28 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1219 */{ 3 , 1 , 18 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1220 */{ 0 , 2 , 6 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1221 */{ 12 , 1 , 25 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 29 384
+1222 */{ 0 , 2 , 13 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1223 */{ 0 , 2 , 2 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1224 */{ 8 , 1 , 22 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1225 */{ 0 , 2 , 9 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1226 */{ 0 , 1 , 30 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1227 */{ 5 , 1 , 19 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+1228 */{ 0 , 2 , 8 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1229 */{ 0 , 1 , 27 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1230 */{ 2 , 1 , 16 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+1231 */{ 0 , 2 , 4 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1232 */{ 9 , 1 , 24 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1233 */{ 0 , 2 , 11 , 45728 },/* 30 29 30 30 29 29 30 29 30 29 30 29 0 354
+1234 */{ 0 , 1 , 31 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1235 */{ 7 , 1 , 21 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1236 */{ 0 , 2 , 9 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1237 */{ 0 , 1 , 28 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+1238 */{ 4 , 1 , 18 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1239 */{ 0 , 2 , 6 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1240 */{ 12 , 1 , 26 , 43320 },/* 30 29 30 29 30 29 29 30 29 29 30 30 30 384
+1241 */{ 0 , 2 , 13 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 0 354
+1242 */{ 0 , 2 , 2 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1243 */{ 8 , 1 , 22 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1244 */{ 0 , 2 , 10 , 44624 },/* 30 29 30 29 30 30 30 29 29 30 29 30 0 355
+1245 */{ 0 , 1 , 30 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1246 */{ 4 , 1 , 19 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1247 */{ 0 , 2 , 7 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1248 */{ 0 , 1 , 28 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 0 354
+1249 */{ 2 , 1 , 16 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 29 383
+1250 */{ 0 , 2 , 3 , 58672 },/* 30 30 30 29 29 30 29 30 29 29 30 30 0 355
+1251 */{ 10 , 1 , 24 , 27800 },/* 29 30 30 29 30 30 29 29 30 29 29 30 30 384
+1252 */{ 0 , 2 , 12 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1253 */{ 0 , 1 , 31 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1254 */{ 6 , 1 , 21 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1255 */{ 0 , 2 , 9 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1256 */{ 0 , 1 , 29 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+1257 */{ 4 , 1 , 17 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1258 */{ 0 , 2 , 5 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1259 */{ 11 , 1 , 25 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1260 */{ 0 , 2 , 13 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1261 */{ 0 , 2 , 1 , 46752 },/* 30 29 30 30 29 30 30 29 30 29 30 29 0 355
+1262 */{ 9 , 1 , 22 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 29 384
+1263 */{ 0 , 2 , 10 , 21872 },/* 29 30 29 30 29 30 29 30 29 30 30 30 0 355
+1264 */{ 0 , 1 , 31 , 18896 },/* 29 30 29 29 30 29 29 30 30 30 29 30 0 354
+1265 */{ 5 , 1 , 19 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1266 */{ 0 , 2 , 7 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1267 */{ 0 , 1 , 27 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1268 */{ 1 , 1 , 16 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+1269 */{ 0 , 2 , 3 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1270 */{ 11 , 1 , 23 , 46528 },/* 30 29 30 30 29 30 29 30 30 30 29 29 29 384
+1271 */{ 0 , 2 , 11 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1272 */{ 0 , 2 , 1 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1273 */{ 6 , 1 , 21 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1274 */{ 0 , 2 , 9 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1275 */{ 0 , 1 , 29 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1276 */{ 3 , 1 , 18 , 27224 },/* 29 30 30 29 30 29 30 29 29 30 29 30 30 384
+1277 */{ 0 , 2 , 5 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1278 */{ 11 , 1 , 25 , 27432 },/* 29 30 30 29 30 29 30 30 29 29 30 29 30 384
+1279 */{ 0 , 2 , 13 , 23232 },/* 29 30 29 30 30 29 30 29 30 30 29 29 0 354
+1280 */{ 0 , 2 , 2 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1281 */{ 8 , 1 , 22 , 10984 },/* 29 29 30 29 30 29 30 29 30 30 30 29 30 384
+1282 */{ 0 , 2 , 10 , 18912 },/* 29 30 29 29 30 29 29 30 30 30 30 29 0 354
+1283 */{ 0 , 1 , 30 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1284 */{ 5 , 1 , 19 , 53848 },/* 30 30 29 30 29 29 30 29 29 30 29 30 30 384
+1285 */{ 0 , 2 , 6 , 45648 },/* 30 29 30 30 29 29 30 29 29 30 29 30 0 354
+1286 */{ 0 , 1 , 26 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1287 */{ 2 , 1 , 15 , 62096 },/* 30 30 30 30 29 29 30 29 30 29 29 30 29 384
+1288 */{ 0 , 2 , 3 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+1289 */{ 10 , 1 , 23 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 29 384
+1290 */{ 0 , 2 , 11 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1291 */{ 0 , 2 , 1 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1292 */{ 6 , 1 , 21 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1293 */{ 0 , 2 , 8 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1294 */{ 0 , 1 , 28 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1295 */{ 4 , 1 , 17 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+1296 */{ 0 , 2 , 5 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1297 */{ 12 , 1 , 24 , 44384 },/* 30 29 30 29 30 30 29 30 29 30 30 29 29 384
+1298 */{ 0 , 2 , 12 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1299 */{ 0 , 2 , 2 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1300 */{ 8 , 1 , 23 , 2424 },/* 29 29 29 29 30 29 29 30 29 30 30 30 30 383
+1301 */{ 0 , 2 , 10 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1302 */{ 0 , 1 , 30 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1303 */{ 5 , 1 , 19 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1304 */{ 0 , 2 , 6 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+1305 */{ 0 , 1 , 26 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1306 */{ 1 , 1 , 15 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 29 384
+1307 */{ 0 , 2 , 3 , 42720 },/* 30 29 30 29 29 30 30 29 30 30 30 29 0 355
+1308 */{ 11 , 1 , 24 , 37608 },/* 30 29 29 30 29 29 30 29 30 30 30 29 30 384
+1309 */{ 0 , 2 , 11 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1310 */{ 0 , 1 , 31 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1311 */{ 7 , 1 , 20 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1312 */{ 0 , 2 , 8 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1313 */{ 0 , 1 , 27 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1314 */{ 3 , 1 , 17 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1315 */{ 0 , 2 , 5 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1316 */{ 0 , 1 , 25 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+1317 */{ 1 , 1 , 14 , 37608 },/* 30 29 29 30 29 29 30 29 30 30 30 29 30 384
+1318 */{ 0 , 2 , 2 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+1319 */{ 8 , 1 , 22 , 42328 },/* 30 29 30 29 29 30 29 30 29 30 29 30 30 384
+1320 */{ 0 , 2 , 10 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1321 */{ 0 , 1 , 29 , 45728 },/* 30 29 30 30 29 29 30 29 30 29 30 29 0 354
+1322 */{ 5 , 1 , 18 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1323 */{ 0 , 2 , 6 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1324 */{ 0 , 1 , 27 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1325 */{ 1 , 1 , 15 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 29 384
+1326 */{ 0 , 2 , 3 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1327 */{ 9 , 1 , 24 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1328 */{ 0 , 2 , 12 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 0 354
+1329 */{ 0 , 1 , 31 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 0 354
+1330 */{ 7 , 1 , 20 , 27288 },/* 29 30 30 29 30 29 30 29 30 29 29 30 30 384
+1331 */{ 0 , 2 , 8 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1332 */{ 0 , 1 , 28 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1333 */{ 3 , 1 , 17 , 19368 },/* 29 30 29 29 30 29 30 30 30 29 30 29 30 384
+1334 */{ 0 , 2 , 5 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1335 */{ 12 , 1 , 25 , 42608 },/* 30 29 30 29 29 30 30 29 29 30 30 30 29 384
+1336 */{ 0 , 2 , 13 , 41696 },/* 30 29 30 29 29 29 30 29 30 30 30 29 0 354
+1337 */{ 0 , 2 , 1 , 53600 },/* 30 30 29 30 29 29 29 30 29 30 30 29 0 354
+1338 */{ 8 , 1 , 21 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1339 */{ 0 , 2 , 9 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1340 */{ 0 , 1 , 29 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+1341 */{ 5 , 1 , 18 , 23376 },/* 29 30 29 30 30 29 30 30 29 30 29 30 29 384
+1342 */{ 0 , 2 , 6 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1343 */{ 0 , 1 , 27 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1344 */{ 2 , 1 , 16 , 41704 },/* 30 29 30 29 29 29 30 29 30 30 30 29 30 384
+1345 */{ 0 , 2 , 3 , 41680 },/* 30 29 30 29 29 29 30 29 30 30 29 30 0 354
+1346 */{ 10 , 1 , 23 , 53592 },/* 30 30 29 30 29 29 29 30 29 30 29 30 30 384
+1347 */{ 0 , 2 , 11 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1348 */{ 0 , 1 , 31 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1349 */{ 7 , 1 , 19 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 29 384
+1350 */{ 0 , 2 , 7 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+1351 */{ 0 , 1 , 28 , 21968 },/* 29 30 29 30 29 30 29 30 30 30 29 30 0 355
+1352 */{ 3 , 1 , 18 , 18904 },/* 29 30 29 29 30 29 29 30 30 30 29 30 30 384
+1353 */{ 0 , 2 , 5 , 17840 },/* 29 30 29 29 29 30 29 30 30 29 30 30 0 354
+1354 */{ 0 , 1 , 25 , 41648 },/* 30 29 30 29 29 29 30 29 30 29 30 30 0 354
+1355 */{ 1 , 1 , 14 , 53592 },/* 30 30 29 30 29 29 29 30 29 30 29 30 30 384
+1356 */{ 0 , 2 , 2 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1357 */{ 9 , 1 , 21 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+1358 */{ 0 , 2 , 9 , 27424 },/* 29 30 30 29 30 29 30 30 29 29 30 29 0 354
+1359 */{ 0 , 1 , 29 , 44384 },/* 30 29 30 29 30 30 29 30 29 30 30 29 0 355
+1360 */{ 5 , 1 , 19 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+1361 */{ 0 , 2 , 6 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1362 */{ 0 , 1 , 27 , 17776 },/* 29 30 29 29 29 30 29 30 29 30 30 30 0 354
+1363 */{ 3 , 1 , 16 , 41656 },/* 30 29 30 29 29 29 30 29 30 29 30 30 30 384
+1364 */{ 0 , 2 , 4 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1365 */{ 10 , 1 , 23 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 29 383
+1366 */{ 0 , 2 , 10 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1367 */{ 0 , 1 , 31 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1368 */{ 7 , 1 , 20 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 29 384
+1369 */{ 0 , 2 , 7 , 42720 },/* 30 29 30 29 29 30 30 29 30 30 30 29 0 355
+1370 */{ 0 , 1 , 28 , 21216 },/* 29 30 29 30 29 29 30 29 30 30 30 29 0 354
+1371 */{ 3 , 1 , 17 , 50544 },/* 30 30 29 29 29 30 29 30 29 30 30 30 29 384
+1372 */{ 0 , 2 , 5 , 42336 },/* 30 29 30 29 29 30 29 30 29 30 30 29 0 354
+1373 */{ 11 , 1 , 24 , 53928 },/* 30 30 29 30 29 29 30 29 30 29 30 29 30 384
+1374 */{ 0 , 2 , 12 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+1375 */{ 0 , 2 , 1 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1376 */{ 9 , 1 , 22 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1377 */{ 0 , 2 , 9 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1378 */{ 0 , 1 , 29 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+1379 */{ 5 , 1 , 19 , 21224 },/* 29 30 29 30 29 29 30 29 30 30 30 29 30 384
+1380 */{ 0 , 2 , 7 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1381 */{ 0 , 1 , 26 , 43216 },/* 30 29 30 29 30 29 29 29 30 30 29 30 0 354
+1382 */{ 2 , 1 , 15 , 53928 },/* 30 30 29 30 29 29 30 29 30 29 30 29 30 384
+1383 */{ 0 , 2 , 3 , 45728 },/* 30 29 30 30 29 29 30 29 30 29 30 29 0 354
+1384 */{ 10 , 1 , 23 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1385 */{ 0 , 2 , 10 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1386 */{ 0 , 1 , 31 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1387 */{ 6 , 1 , 20 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 29 384
+1388 */{ 0 , 2 , 8 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1389 */{ 0 , 1 , 28 , 20912 },/* 29 30 29 30 29 29 29 30 30 29 30 30 0 354
+1390 */{ 4 , 1 , 17 , 43192 },/* 30 29 30 29 30 29 29 29 30 29 30 30 30 384
+1391 */{ 0 , 2 , 5 , 25904 },/* 29 30 30 29 29 30 29 30 29 29 30 30 0 354
+1392 */{ 12 , 1 , 25 , 27288 },/* 29 30 30 29 30 29 30 29 30 29 29 30 30 384
+1393 */{ 0 , 2 , 12 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1394 */{ 0 , 2 , 1 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1395 */{ 9 , 1 , 22 , 11176 },/* 29 29 30 29 30 29 30 30 30 29 30 29 30 384
+1396 */{ 0 , 2 , 10 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1397 */{ 0 , 1 , 29 , 50032 },/* 30 30 29 29 29 29 30 30 29 30 30 30 0 355
+1398 */{ 5 , 1 , 19 , 20848 },/* 29 30 29 30 29 29 29 30 29 30 30 30 29 383
+1399 */{ 0 , 2 , 6 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1400 */{ 0 , 1 , 26 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1401 */{ 3 , 1 , 15 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 29 383
+1402 */{ 0 , 2 , 2 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+1403 */{ 11 , 1 , 23 , 23376 },/* 29 30 29 30 30 29 30 30 29 30 29 30 29 384
+1404 */{ 0 , 2 , 11 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1405 */{ 0 , 1 , 31 , 10976 },/* 29 29 30 29 30 29 30 29 30 30 30 29 0 354
+1406 */{ 7 , 1 , 20 , 41704 },/* 30 29 30 29 29 29 30 29 30 30 30 29 30 384
+1407 */{ 0 , 2 , 8 , 41680 },/* 30 29 30 29 29 29 30 29 30 30 29 30 0 354
+1408 */{ 0 , 1 , 28 , 53584 },/* 30 30 29 30 29 29 29 30 29 30 29 30 0 354
+1409 */{ 4 , 1 , 16 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1410 */{ 0 , 2 , 4 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1411 */{ 12 , 1 , 24 , 46736 },/* 30 29 30 30 29 30 30 29 30 29 29 30 29 384
+1412 */{ 0 , 2 , 12 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+1413 */{ 0 , 2 , 1 , 21968 },/* 29 30 29 30 29 30 29 30 30 30 29 30 0 355
+1414 */{ 9 , 1 , 22 , 9688 },/* 29 29 30 29 29 30 29 30 30 30 29 30 30 384
+1415 */{ 0 , 2 , 10 , 17840 },/* 29 30 29 29 29 30 29 30 30 29 30 30 0 354
+1416 */{ 0 , 1 , 30 , 41648 },/* 30 29 30 29 29 29 30 29 30 29 30 30 0 354
+1417 */{ 5 , 1 , 18 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1418 */{ 0 , 2 , 6 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1419 */{ 0 , 1 , 26 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1420 */{ 1 , 1 , 15 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1421 */{ 0 , 2 , 2 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1422 */{ 12 , 1 , 23 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+1423 */{ 0 , 2 , 11 , 19312 },/* 29 30 29 29 30 29 30 30 29 30 30 30 0 355
+1424 */{ 0 , 2 , 1 , 17776 },/* 29 30 29 29 29 30 29 30 29 30 30 30 0 354
+1425 */{ 7 , 1 , 20 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1426 */{ 0 , 2 , 8 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1427 */{ 0 , 1 , 28 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1428 */{ 4 , 1 , 17 , 27816 },/* 29 30 30 29 30 30 29 29 30 29 30 29 30 384
+1429 */{ 0 , 2 , 4 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1430 */{ 12 , 1 , 24 , 39760 },/* 30 29 29 30 30 29 30 30 29 30 29 30 29 384
+1431 */{ 0 , 2 , 12 , 42720 },/* 30 29 30 29 29 30 30 29 30 30 30 29 0 355
+1432 */{ 0 , 2 , 2 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1433 */{ 8 , 1 , 21 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1434 */{ 0 , 2 , 9 , 42336 },/* 30 29 30 29 29 30 29 30 29 30 30 29 0 354
+1435 */{ 0 , 1 , 29 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+1436 */{ 6 , 1 , 18 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 29 384
+1437 */{ 0 , 2 , 5 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1438 */{ 0 , 1 , 26 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1439 */{ 2 , 1 , 15 , 43728 },/* 30 29 30 29 30 29 30 29 30 30 29 30 29 384
+1440 */{ 0 , 2 , 3 , 38368 },/* 30 29 29 30 29 30 29 30 30 30 30 29 0 355
+1441 */{ 11 , 1 , 23 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1442 */{ 0 , 2 , 11 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1443 */{ 0 , 1 , 31 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1444 */{ 7 , 1 , 20 , 53872 },/* 30 30 29 30 29 29 30 29 29 30 30 30 29 384
+1445 */{ 0 , 2 , 7 , 45728 },/* 30 29 30 30 29 29 30 29 30 29 30 29 0 354
+1446 */{ 0 , 1 , 27 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1447 */{ 4 , 1 , 17 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1448 */{ 0 , 2 , 5 , 11680 },/* 29 29 30 29 30 30 29 30 30 29 30 29 0 354
+1449 */{ 0 , 1 , 24 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1450 */{ 1 , 1 , 14 , 19128 },/* 29 30 29 29 30 29 30 29 30 29 30 30 30 384
+1451 */{ 0 , 2 , 2 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1452 */{ 9 , 1 , 22 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1453 */{ 0 , 2 , 9 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1454 */{ 0 , 1 , 29 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 0 354
+1455 */{ 6 , 1 , 18 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1456 */{ 0 , 2 , 6 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 0 355
+1457 */{ 0 , 1 , 26 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1458 */{ 2 , 1 , 15 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 29 384
+1459 */{ 0 , 2 , 3 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1460 */{ 11 , 1 , 24 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 29 383
+1461 */{ 0 , 2 , 10 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1462 */{ 0 , 1 , 30 , 58544 },/* 30 30 30 29 29 30 29 29 30 29 30 30 0 355
+1463 */{ 7 , 1 , 20 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 29 383
+1464 */{ 0 , 2 , 7 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+1465 */{ 0 , 1 , 27 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1466 */{ 3 , 1 , 17 , 11112 },/* 29 29 30 29 30 29 30 30 29 30 30 29 30 384
+1467 */{ 0 , 2 , 5 , 9952 },/* 29 29 30 29 29 30 30 29 30 30 30 29 0 354
+1468 */{ 0 , 1 , 25 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1469 */{ 2 , 1 , 13 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1470 */{ 0 , 2 , 1 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1471 */{ 9 , 1 , 21 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1472 */{ 0 , 2 , 9 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1473 */{ 0 , 1 , 28 , 46736 },/* 30 29 30 30 29 30 30 29 30 29 29 30 0 355
+1474 */{ 6 , 1 , 18 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 29 384
+1475 */{ 0 , 2 , 6 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1476 */{ 0 , 1 , 27 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1477 */{ 2 , 1 , 15 , 37592 },/* 30 29 29 30 29 29 30 29 30 30 29 30 30 384
+1478 */{ 0 , 2 , 3 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+1479 */{ 10 , 1 , 23 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1480 */{ 0 , 2 , 11 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1481 */{ 0 , 1 , 30 , 29856 },/* 29 30 30 30 29 30 29 29 30 29 30 29 0 354
+1482 */{ 8 , 1 , 19 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1483 */{ 0 , 2 , 7 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1484 */{ 0 , 1 , 28 , 21424 },/* 29 30 29 30 29 29 30 30 30 29 30 30 0 355
+1485 */{ 4 , 1 , 17 , 9656 },/* 29 29 30 29 29 30 29 30 30 29 30 30 30 384
+1486 */{ 0 , 2 , 5 , 9584 },/* 29 29 30 29 29 30 29 30 29 30 30 30 0 354
+1487 */{ 0 , 1 , 25 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1488 */{ 1 , 1 , 14 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1489 */{ 0 , 2 , 1 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1490 */{ 9 , 1 , 21 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1491 */{ 0 , 2 , 9 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1492 */{ 0 , 1 , 29 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1493 */{ 5 , 1 , 18 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1494 */{ 0 , 2 , 6 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1495 */{ 0 , 1 , 26 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1496 */{ 3 , 1 , 16 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 29 383
+1497 */{ 0 , 2 , 2 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+1498 */{ 11 , 1 , 22 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 29 384
+1499 */{ 0 , 2 , 10 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1500 */{ 0 , 1 , 31 , 5792 },/* 29 29 29 30 29 30 30 29 30 29 30 29 0 353
+1501 */{ 7 , 1 , 19 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1502 */{ 0 , 2 , 7 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1503 */{ 0 , 1 , 28 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1504 */{ 4 , 1 , 17 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1505 */{ 0 , 2 , 4 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1506 */{ 0 , 1 , 24 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1507 */{ 1 , 1 , 13 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 29 384
+1508 */{ 0 , 2 , 1 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1509 */{ 9 , 1 , 21 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1510 */{ 0 , 2 , 9 , 11680 },/* 29 29 30 29 30 30 29 30 30 29 30 29 0 354
+1511 */{ 0 , 1 , 29 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1512 */{ 5 , 1 , 19 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1513 */{ 0 , 2 , 6 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1514 */{ 0 , 1 , 26 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1515 */{ 4 , 1 , 15 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1516 */{ 0 , 2 , 3 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 0 354
+1517 */{ 12 , 1 , 22 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1518 */{ 0 , 2 , 10 , 23376 },/* 29 30 29 30 30 29 30 30 29 30 29 30 0 355
+1519 */{ 0 , 1 , 31 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1520 */{ 8 , 1 , 20 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 29 384
+1521 */{ 0 , 2 , 7 , 37616 },/* 30 29 29 30 29 29 30 29 30 30 30 30 0 355
+1522 */{ 0 , 1 , 28 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1523 */{ 4 , 1 , 17 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1524 */{ 0 , 2 , 4 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1525 */{ 12 , 1 , 23 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 29 384
+1526 */{ 0 , 2 , 11 , 54928 },/* 30 30 29 30 29 30 30 29 30 29 29 30 0 355
+1527 */{ 0 , 2 , 1 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1528 */{ 10 , 1 , 22 , 11112 },/* 29 29 30 29 30 29 30 30 29 30 30 29 30 384
+1529 */{ 0 , 2 , 9 , 9952 },/* 29 29 30 29 29 30 30 29 30 30 30 29 0 354
+1530 */{ 0 , 1 , 29 , 21216 },/* 29 30 29 30 29 29 30 29 30 30 30 29 0 354
+1531 */{ 6 , 1 , 18 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1532 */{ 0 , 2 , 6 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1533 */{ 0 , 1 , 25 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1534 */{ 2 , 1 , 14 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1535 */{ 0 , 2 , 2 , 46480 },/* 30 29 30 30 29 30 29 30 30 29 29 30 0 355
+1536 */{ 12 , 1 , 23 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 29 384
+1537 */{ 0 , 2 , 10 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1538 */{ 0 , 1 , 31 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1539 */{ 7 , 1 , 20 , 37592 },/* 30 29 29 30 29 29 30 29 30 30 29 30 30 384
+1540 */{ 0 , 2 , 8 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+1541 */{ 0 , 1 , 27 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1542 */{ 5 , 1 , 16 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+1543 */{ 0 , 2 , 4 , 27808 },/* 29 30 30 29 30 30 29 29 30 29 30 29 0 354
+1544 */{ 0 , 1 , 24 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1545 */{ 1 , 1 , 13 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+1546 */{ 0 , 2 , 1 , 19376 },/* 29 30 29 29 30 29 30 30 30 29 30 30 0 355
+1547 */{ 9 , 1 , 22 , 9656 },/* 29 29 30 29 29 30 29 30 30 29 30 30 30 384
+1548 */{ 0 , 2 , 10 , 9584 },/* 29 29 30 29 29 30 29 30 29 30 30 30 0 354
+1549 */{ 0 , 1 , 29 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1550 */{ 6 , 1 , 18 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 29 383
+1551 */{ 0 , 2 , 5 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+1552 */{ 0 , 1 , 26 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1553 */{ 3 , 1 , 14 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1554 */{ 0 , 2 , 2 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1555 */{ 11 , 1 , 23 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1556 */{ 0 , 2 , 11 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1557 */{ 0 , 1 , 30 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1558 */{ 7 , 1 , 20 , 21096 },/* 29 30 29 30 29 29 30 29 29 30 30 29 30 383
+1559 */{ 0 , 2 , 7 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1560 */{ 0 , 1 , 27 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1561 */{ 5 , 1 , 16 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1562 */{ 0 , 2 , 4 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1563 */{ 0 , 1 , 24 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1564 */{ 2 , 1 , 14 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1565 */{ 0 , 2 , 1 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1566 */{ 10 , 1 , 21 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1567 */{ 0 , 2 , 9 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1568 */{ 0 , 1 , 29 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1569 */{ 6 , 1 , 17 , 54600 },/* 30 30 29 30 29 30 29 30 29 30 29 29 30 384
+1570 */{ 0 , 2 , 5 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1571 */{ 0 , 1 , 26 , 13728 },/* 29 29 30 30 29 30 29 30 30 29 30 29 0 354
+1572 */{ 2 , 1 , 15 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 29 384
+1573 */{ 0 , 2 , 2 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1574 */{ 12 , 1 , 23 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1575 */{ 0 , 2 , 11 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1576 */{ 0 , 1 , 31 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1577 */{ 8 , 1 , 19 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1578 */{ 0 , 2 , 7 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1579 */{ 0 , 1 , 27 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1580 */{ 4 , 1 , 16 , 44456 },/* 30 29 30 29 30 30 29 30 30 29 30 29 30 385
+1581 */{ 0 , 2 , 4 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1582 */{ 0 , 1 , 24 , 39024 },/* 30 29 29 30 29 29 30 30 39 30 30 30 0 365
+1583 */{ 2 , 1 , 24 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1584 */{ 0 , 2 , 12 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1585 */{ 9 , 1 , 31 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1586 */{ 0 , 2 , 18 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1587 */{ 0 , 3 , 9 , 53968 },/* 30 30 29 30 29 30 29 29 30 29 30 0 0 325
+1588 */{ 6 , 1 , 28 , 27464 },/* 29 30 30 29 30 29 30 30 29 30 29 29 30 384
+1589 */{ 0 , 2 , 15 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1590 */{ 0 , 2 , 5 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1591 */{ 3 , 1 , 25 , 37616 },/* 30 29 29 30 29 29 30 29 30 30 30 30 29 384
+1592 */{ 0 , 2 , 13 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1593 */{ 11 , 2 , 1 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1594 */{ 0 , 2 , 20 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1595 */{ 0 , 2 , 9 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1596 */{ 8 , 1 , 29 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1597 */{ 0 , 2 , 16 , 46288 },/* 30 29 30 30 29 30 29 29 30 30 29 30 0 355
+1598 */{ 0 , 2 , 6 , 22192 },/* 29 30 29 30 29 30 30 29 30 29 30 30 0 355
+1599 */{ 4 , 1 , 27 , 9944 },/* 29 29 30 29 29 30 30 29 30 30 29 30 30 384
+1600 */{ 0 , 2 , 15 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1601 */{ 0 , 2 , 3 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+1602 */{ 2 , 1 , 23 , 51608 },/* 30 30 29 29 30 29 29 30 30 29 29 30 30 384
+1603 */{ 0 , 2 , 11 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1604 */{ 9 , 1 , 31 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+1605 */{ 0 , 2 , 18 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1606 */{ 0 , 2 , 7 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1607 */{ 6 , 1 , 28 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+1608 */{ 0 , 2 , 16 , 19376 },/* 29 30 29 29 30 29 30 30 30 29 30 30 0 355
+1609 */{ 0 , 2 , 5 , 9648 },/* 29 29 30 29 29 30 29 30 30 29 30 30 0 354
+1610 */{ 3 , 1 , 25 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1611 */{ 0 , 2 , 13 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1612 */{ 11 , 2 , 2 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 29 383
+1613 */{ 0 , 2 , 19 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+1614 */{ 0 , 2 , 9 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1615 */{ 8 , 1 , 29 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1616 */{ 0 , 2 , 17 , 39760 },/* 30 29 29 30 30 29 30 30 29 30 29 30 0 355
+1617 */{ 0 , 2 , 6 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1618 */{ 4 , 1 , 26 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1619 */{ 0 , 2 , 14 , 42224 },/* 30 29 30 29 29 30 29 29 30 30 30 30 0 355
+1620 */{ 0 , 2 , 4 , 21088 },/* 29 30 29 30 29 29 30 29 29 30 30 29 0 353
+1621 */{ 2 , 1 , 22 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1622 */{ 0 , 2 , 10 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1623 */{ 10 , 1 , 31 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1624 */{ 0 , 2 , 19 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1625 */{ 0 , 2 , 7 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1626 */{ 6 , 1 , 28 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1627 */{ 0 , 2 , 16 , 18912 },/* 29 30 29 29 30 29 29 30 30 30 30 29 0 354
+1628 */{ 0 , 2 , 5 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1629 */{ 4 , 1 , 24 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1630 */{ 0 , 2 , 12 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1631 */{ 11 , 2 , 1 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1632 */{ 0 , 2 , 20 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1633 */{ 0 , 2 , 8 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+1634 */{ 8 , 1 , 29 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 29 384
+1635 */{ 0 , 2 , 17 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1636 */{ 0 , 2 , 7 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1637 */{ 4 , 1 , 26 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1638 */{ 0 , 2 , 14 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1639 */{ 0 , 2 , 3 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1640 */{ 1 , 1 , 23 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+1641 */{ 0 , 2 , 10 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1642 */{ 11 , 1 , 30 , 44456 },/* 30 29 30 29 30 30 29 30 30 29 30 29 30 385
+1643 */{ 0 , 2 , 19 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1644 */{ 0 , 2 , 8 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1645 */{ 6 , 1 , 28 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1646 */{ 0 , 2 , 16 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1647 */{ 0 , 2 , 5 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1648 */{ 3 , 1 , 24 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1649 */{ 0 , 2 , 11 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+1650 */{ 11 , 2 , 1 , 27464 },/* 29 30 30 29 30 29 30 30 29 30 29 29 30 384
+1651 */{ 0 , 2 , 20 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1652 */{ 0 , 2 , 10 , 11168 },/* 29 29 30 29 30 29 30 30 30 29 30 29 0 354
+1653 */{ 7 , 1 , 29 , 37616 },/* 30 29 29 30 29 29 30 29 30 30 30 30 29 384
+1654 */{ 0 , 2 , 17 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1655 */{ 0 , 2 , 6 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1656 */{ 5 , 1 , 26 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1657 */{ 0 , 2 , 13 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1658 */{ 0 , 2 , 2 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+1659 */{ 3 , 1 , 23 , 39592 },/* 30 29 29 30 30 29 30 29 30 29 30 29 30 384
+1660 */{ 0 , 2 , 11 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1661 */{ 7 , 1 , 30 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 29 384
+1662 */{ 0 , 2 , 18 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 0 355
+1663 */{ 0 , 2 , 8 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+1664 */{ 6 , 1 , 28 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1665 */{ 0 , 2 , 15 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1666 */{ 0 , 2 , 4 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1667 */{ 4 , 1 , 24 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1668 */{ 0 , 2 , 12 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1669 */{ 0 , 2 , 1 , 21920 },/* 29 30 29 30 29 30 29 30 30 29 30 29 0 354
+1670 */{ 2 , 1 , 21 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 29 384
+1671 */{ 0 , 2 , 9 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+1672 */{ 7 , 1 , 30 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1673 */{ 0 , 2 , 17 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1674 */{ 0 , 2 , 6 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 0 354
+1675 */{ 5 , 1 , 26 , 29864 },/* 29 30 30 30 29 30 29 29 30 29 30 29 30 384
+1676 */{ 0 , 2 , 14 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1677 */{ 0 , 2 , 2 , 44432 },/* 30 29 30 29 30 30 29 30 30 29 29 30 0 355
+1678 */{ 3 , 1 , 23 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+1679 */{ 0 , 2 , 11 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1680 */{ 8 , 1 , 31 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1681 */{ 0 , 2 , 18 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+1682 */{ 0 , 2 , 7 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1683 */{ 6 , 1 , 27 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1684 */{ 0 , 2 , 15 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+1685 */{ 0 , 2 , 3 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+1686 */{ 4 , 1 , 24 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+1687 */{ 0 , 2 , 12 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1688 */{ 0 , 2 , 2 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1689 */{ 3 , 1 , 21 , 42216 },/* 30 29 30 29 29 30 29 29 30 30 30 29 30 384
+1690 */{ 0 , 2 , 9 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1691 */{ 7 , 1 , 29 , 53848 },/* 30 30 29 30 29 29 30 29 29 30 29 30 30 384
+1692 */{ 0 , 2 , 17 , 45136 },/* 30 29 29 32 29 29 29 29 29 30 29 30 0 354
+1693 */{ 0 , 2 , 5 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+1694 */{ 5 , 1 , 25 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 29 384
+1695 */{ 0 , 2 , 13 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+1696 */{ 0 , 2 , 3 , 21968 },/* 29 30 29 30 29 30 29 30 30 30 29 30 0 355
+1697 */{ 3 , 1 , 23 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+1698 */{ 0 , 2 , 11 , 18896 },/* 29 30 29 29 30 29 29 30 30 30 29 30 0 354
+1699 */{ 7 , 1 , 31 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1700 */{ 0 , 2 , 19 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1701 */{ 0 , 2 , 8 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1702 */{ 6 , 1 , 28 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+1703 */{ 0 , 2 , 16 , 27936 },/* 29 30 30 29 30 30 29 30 29 29 30 29 0 354
+1704 */{ 0 , 2 , 5 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+1705 */{ 4 , 1 , 25 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+1706 */{ 0 , 2 , 13 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1707 */{ 0 , 2 , 3 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1708 */{ 3 , 1 , 23 , 25784 },/* 29 30 30 29 29 30 29 29 30 29 30 30 30 384
+1709 */{ 0 , 2 , 10 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1710 */{ 7 , 1 , 30 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1711 */{ 0 , 2 , 17 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+1712 */{ 0 , 2 , 7 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1713 */{ 5 , 1 , 26 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 29 384
+1714 */{ 0 , 2 , 14 , 43744 },/* 30 29 30 29 30 29 30 29 30 30 30 29 0 355
+1715 */{ 0 , 2 , 4 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1716 */{ 3 , 1 , 24 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 29 384
+1717 */{ 0 , 2 , 11 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+1718 */{ 8 , 1 , 31 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1719 */{ 0 , 2 , 19 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1720 */{ 0 , 2 , 8 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1721 */{ 6 , 1 , 28 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1722 */{ 0 , 2 , 16 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1723 */{ 0 , 2 , 5 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+1724 */{ 4 , 1 , 26 , 21224 },/* 29 30 29 30 29 29 30 29 30 30 30 29 30 384
+1725 */{ 0 , 2 , 13 , 21200 },/* 29 30 29 30 29 29 30 29 30 30 29 30 0 354
+1726 */{ 0 , 2 , 2 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1727 */{ 3 , 1 , 22 , 58536 },/* 30 30 30 29 29 30 29 29 30 29 30 29 30 384
+1728 */{ 0 , 2 , 10 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1729 */{ 7 , 1 , 29 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1730 */{ 0 , 2 , 17 , 40272 },/* 30 29 29 30 30 30 29 30 29 30 29 30 0 355
+1731 */{ 0 , 2 , 7 , 21920 },/* 29 30 29 30 29 30 29 30 30 29 30 29 0 354
+1732 */{ 5 , 1 , 27 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 29 384
+1733 */{ 0 , 2 , 14 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+1734 */{ 0 , 2 , 4 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1735 */{ 4 , 1 , 24 , 43192 },/* 30 29 30 29 30 29 29 29 30 29 30 30 30 384
+1736 */{ 0 , 2 , 12 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 0 354
+1737 */{ 9 , 1 , 31 , 27288 },/* 29 30 30 29 30 29 30 29 30 29 29 30 30 384
+1738 */{ 0 , 2 , 19 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1739 */{ 0 , 2 , 8 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1740 */{ 6 , 1 , 29 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+1741 */{ 0 , 2 , 16 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1742 */{ 0 , 2 , 5 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1743 */{ 4 , 1 , 26 , 20848 },/* 29 30 29 30 29 29 29 30 29 30 30 30 29 383
+1744 */{ 0 , 2 , 13 , 53600 },/* 30 30 29 30 29 29 29 30 29 30 30 29 0 354
+1745 */{ 0 , 2 , 1 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 0 355
+1746 */{ 3 , 1 , 22 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 29 383
+1747 */{ 0 , 2 , 9 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+1748 */{ 7 , 1 , 30 , 23376 },/* 29 30 29 30 30 29 30 30 29 30 29 30 29 384
+1749 */{ 0 , 2 , 17 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1750 */{ 0 , 2 , 7 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1751 */{ 5 , 1 , 27 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1752 */{ 0 , 2 , 15 , 41680 },/* 30 29 30 29 29 29 30 29 30 30 29 30 0 354
+1753 */{ 0 , 2 , 3 , 53592 },/* 30 30 29 30 29 29 29 30 29 30 29 30 30 384
+1754 */{ 4 , 2 , 22 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+1755 */{ 0 , 2 , 11 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1756 */{ 9 , 1 , 31 , 54928 },/* 30 30 29 30 29 30 30 29 30 29 29 30 29 384
+1757 */{ 0 , 2 , 18 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+1758 */{ 0 , 2 , 8 , 21968 },/* 29 30 29 30 29 30 29 30 30 30 29 30 0 355
+1759 */{ 6 , 1 , 29 , 10968 },/* 29 29 30 29 30 29 30 29 30 30 29 30 30 384
+1760 */{ 0 , 2 , 17 , 17840 },/* 29 30 29 29 29 30 29 30 30 29 30 30 0 354
+1761 */{ 0 , 2 , 5 , 41648 },/* 30 29 30 29 29 29 30 29 30 29 30 30 0 354
+1762 */{ 5 , 1 , 25 , 45400 },/* 30 29 30 30 29 29 29 30 29 30 29 30 30 384
+1763 */{ 0 , 2 , 13 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1764 */{ 0 , 2 , 2 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1765 */{ 2 , 1 , 21 , 46480 },/* 30 29 30 30 29 30 29 30 30 29 29 30 29 384
+1766 */{ 0 , 2 , 9 , 44384 },/* 30 29 30 29 30 30 29 30 29 30 30 29 0 355
+1767 */{ 7 , 1 , 30 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+1768 */{ 0 , 2 , 18 , 21360 },/* 29 30 29 30 29 29 30 30 29 30 30 30 0 355
+1769 */{ 0 , 2 , 7 , 17776 },/* 29 30 29 29 29 30 29 30 29 30 30 30 0 354
+1770 */{ 5 , 1 , 27 , 25272 },/* 29 30 30 29 29 29 30 29 30 29 30 30 30 384
+1771 */{ 0 , 2 , 15 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1772 */{ 0 , 2 , 4 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1773 */{ 3 , 1 , 23 , 27816 },/* 29 30 30 29 30 30 29 29 30 29 30 29 30 384
+1774 */{ 0 , 2 , 11 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1775 */{ 10 , 1 , 31 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 29 384
+1776 */{ 0 , 2 , 19 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+1777 */{ 0 , 2 , 8 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1778 */{ 6 , 1 , 28 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 29 384
+1779 */{ 0 , 2 , 16 , 42336 },/* 30 29 30 29 29 30 29 30 29 30 30 29 0 354
+1780 */{ 0 , 2 , 5 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+1781 */{ 5 , 1 , 24 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 29 384
+1782 */{ 0 , 2 , 12 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1783 */{ 0 , 2 , 2 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1784 */{ 3 , 1 , 22 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 29 384
+1785 */{ 0 , 2 , 9 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+1786 */{ 7 , 1 , 30 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1787 */{ 0 , 2 , 18 , 19120 },/* 29 30 29 29 30 29 30 29 30 29 30 30 0 354
+1788 */{ 0 , 2 , 7 , 43216 },/* 30 29 30 29 30 29 29 29 30 30 29 30 0 354
+1789 */{ 5 , 1 , 26 , 53928 },/* 30 30 29 30 29 29 30 29 30 29 30 29 30 384
+1790 */{ 0 , 2 , 14 , 45728 },/* 30 29 30 30 29 29 30 29 30 29 30 29 0 354
+1791 */{ 0 , 2 , 3 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1792 */{ 4 , 1 , 24 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1793 */{ 0 , 2 , 11 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1794 */{ 0 , 1 , 31 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1795 */{ 2 , 1 , 21 , 19128 },/* 29 30 29 29 30 29 30 29 30 29 30 30 30 384
+1796 */{ 0 , 2 , 9 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1797 */{ 6 , 1 , 28 , 43192 },/* 30 29 30 29 30 29 29 29 30 29 30 30 30 384
+1798 */{ 0 , 2 , 16 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1799 */{ 0 , 2 , 5 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 0 354
+1800 */{ 4 , 1 , 25 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1801 */{ 0 , 2 , 13 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 0 355
+1802 */{ 0 , 2 , 3 , 11168 },/* 29 29 30 29 30 29 30 30 30 29 30 29 0 354
+1803 */{ 2 , 1 , 23 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 29 384
+1804 */{ 0 , 2 , 11 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1805 */{ 6 , 1 , 31 , 20848 },/* 29 30 29 30 29 29 29 30 29 30 30 30 29 383
+1806 */{ 0 , 2 , 18 , 53600 },/* 30 30 29 30 29 29 29 30 29 30 30 29 0 354
+1807 */{ 0 , 2 , 7 , 58544 },/* 30 30 30 29 29 30 29 29 30 29 30 30 0 355
+1808 */{ 5 , 1 , 28 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 29 383
+1809 */{ 0 , 2 , 14 , 55952 },/* 30 30 29 30 30 29 30 29 30 29 29 30 0 355
+1810 */{ 0 , 2 , 4 , 23376 },/* 29 30 29 30 30 29 30 30 29 30 29 30 0 355
+1811 */{ 3 , 1 , 25 , 11112 },/* 29 29 30 29 30 29 30 30 29 30 30 29 30 384
+1812 */{ 0 , 2 , 13 , 10976 },/* 29 29 30 29 30 29 30 29 30 30 30 29 0 354
+1813 */{ 0 , 2 , 1 , 41696 },/* 30 29 30 29 29 29 30 29 30 30 30 29 0 354
+1814 */{ 2 , 1 , 21 , 53608 },/* 30 30 29 30 29 29 29 30 29 30 30 29 30 384
+1815 */{ 0 , 2 , 9 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1816 */{ 6 , 1 , 29 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1817 */{ 0 , 2 , 16 , 46368 },/* 30 29 30 30 29 30 29 30 29 29 30 29 0 354
+1818 */{ 0 , 2 , 5 , 46736 },/* 30 29 30 30 29 30 30 29 30 29 29 30 0 355
+1819 */{ 4 , 1 , 26 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 29 384
+1820 */{ 0 , 2 , 14 , 21968 },/* 29 30 29 30 29 30 29 30 30 30 29 30 0 355
+1821 */{ 0 , 2 , 3 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1822 */{ 3 , 1 , 23 , 41688 },/* 30 29 30 29 29 29 30 29 30 30 29 30 30 384
+1823 */{ 0 , 2 , 11 , 41648 },/* 30 29 30 29 29 29 30 29 30 29 30 30 0 354
+1824 */{ 7 , 1 , 31 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1825 */{ 0 , 2 , 18 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1826 */{ 0 , 2 , 7 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1827 */{ 5 , 1 , 27 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+1828 */{ 0 , 2 , 15 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+1829 */{ 0 , 2 , 4 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1830 */{ 4 , 1 , 25 , 9656 },/* 29 29 30 29 29 30 29 30 30 29 30 30 30 384
+1831 */{ 0 , 2 , 13 , 9584 },/* 29 29 30 29 29 30 29 30 29 30 30 30 0 354
+1832 */{ 9 , 2 , 2 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1833 */{ 0 , 2 , 20 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1834 */{ 0 , 2 , 9 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1835 */{ 6 , 1 , 29 , 27816 },/* 29 30 30 29 30 30 29 29 30 29 30 29 30 384
+1836 */{ 0 , 2 , 17 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1837 */{ 0 , 2 , 5 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1838 */{ 4 , 1 , 26 , 21352 },/* 29 30 29 30 29 29 30 30 29 30 30 29 30 384
+1839 */{ 0 , 2 , 14 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1840 */{ 0 , 2 , 3 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1841 */{ 3 , 1 , 23 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 29 383
+1842 */{ 0 , 2 , 10 , 53920 },/* 30 30 29 30 29 29 30 29 30 29 30 29 0 354
+1843 */{ 7 , 1 , 30 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 29 384
+1844 */{ 0 , 2 , 18 , 54608 },/* 30 30 29 30 29 30 29 30 29 30 29 30 0 355
+1845 */{ 0 , 2 , 7 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+1846 */{ 5 , 1 , 27 , 43728 },/* 30 29 30 29 30 29 30 29 30 30 29 30 29 384
+1847 */{ 0 , 2 , 15 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1848 */{ 0 , 2 , 5 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1849 */{ 4 , 1 , 24 , 42328 },/* 30 29 30 29 29 30 29 30 29 30 29 30 30 384
+1850 */{ 0 , 2 , 12 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1851 */{ 8 , 2 , 1 , 53848 },/* 30 30 29 30 29 29 30 29 29 30 29 30 30 384
+1852 */{ 0 , 2 , 20 , 45712 },/* 30 29 30 30 29 29 30 29 30 29 29 30 0 354
+1853 */{ 0 , 2 , 8 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1854 */{ 7 , 1 , 29 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1855 */{ 0 , 2 , 17 , 11680 },/* 29 29 30 29 30 30 29 30 30 29 30 29 0 354
+1856 */{ 0 , 2 , 6 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1857 */{ 5 , 1 , 26 , 19128 },/* 29 30 29 29 30 29 30 29 30 29 30 30 30 384
+1858 */{ 0 , 2 , 14 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1859 */{ 0 , 2 , 3 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1860 */{ 3 , 1 , 23 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1861 */{ 0 , 2 , 10 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 0 354
+1862 */{ 8 , 1 , 30 , 44360 },/* 30 29 30 29 30 30 29 30 29 30 29 29 30 384
+1863 */{ 0 , 2 , 18 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 0 355
+1864 */{ 0 , 2 , 8 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1865 */{ 5 , 1 , 27 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 29 384
+1866 */{ 0 , 2 , 15 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+1867 */{ 0 , 2 , 5 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1868 */{ 4 , 1 , 25 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1869 */{ 0 , 2 , 11 , 58528 },/* 30 30 30 29 29 30 29 29 30 29 30 29 0 354
+1870 */{ 10 , 1 , 31 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 29 384
+1871 */{ 0 , 2 , 19 , 55952 },/* 30 30 29 30 30 29 30 29 30 29 29 30 0 355
+1872 */{ 0 , 2 , 9 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1873 */{ 6 , 1 , 29 , 11112 },/* 29 29 30 29 30 29 30 30 29 30 30 29 30 384
+1874 */{ 0 , 2 , 17 , 10976 },/* 29 29 30 29 30 29 30 29 30 30 30 29 0 354
+1875 */{ 0 , 2 , 6 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1876 */{ 5 , 1 , 26 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1877 */{ 0 , 2 , 13 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1878 */{ 0 , 2 , 2 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1879 */{ 3 , 1 , 22 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1880 */{ 0 , 2 , 10 , 46736 },/* 30 29 30 30 29 30 30 29 30 29 29 30 0 355
+1881 */{ 7 , 1 , 30 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 29 384
+1882 */{ 0 , 2 , 18 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1883 */{ 0 , 2 , 8 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1884 */{ 5 , 1 , 28 , 37592 },/* 30 29 29 30 29 29 30 29 30 30 29 30 30 384
+1885 */{ 0 , 2 , 15 , 37552 },/* 30 29 29 30 29 29 30 29 30 29 30 30 0 354
+1886 */{ 0 , 2 , 4 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1887 */{ 4 , 1 , 24 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1888 */{ 0 , 2 , 12 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1889 */{ 0 , 1 , 31 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1890 */{ 2 , 1 , 21 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1891 */{ 0 , 2 , 9 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 0 355
+1892 */{ 6 , 1 , 30 , 9656 },/* 29 29 30 29 29 30 29 30 30 29 30 30 30 384
+1893 */{ 0 , 2 , 17 , 9584 },/* 29 29 30 29 29 30 29 30 29 30 30 30 0 354
+1894 */{ 0 , 2 , 6 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1895 */{ 5 , 1 , 26 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 29 383
+1896 */{ 0 , 2 , 13 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+1897 */{ 0 , 2 , 2 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1898 */{ 3 , 1 , 22 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1899 */{ 0 , 2 , 10 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1900 */{ 8 , 1 , 31 , 19304 },/* 29 30 29 29 30 29 30 30 29 30 30 29 30 384
+1901 */{ 0 , 2 , 19 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1902 */{ 0 , 2 , 8 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1903 */{ 5 , 1 , 29 , 21096 },/* 29 30 29 30 29 29 30 29 29 30 30 29 30 383
+1904 */{ 0 , 2 , 16 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1905 */{ 0 , 2 , 4 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1906 */{ 4 , 1 , 25 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1907 */{ 0 , 2 , 13 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1908 */{ 0 , 2 , 2 , 39632 },/* 30 29 29 30 30 29 30 29 30 30 29 30 0 355
+1909 */{ 2 , 1 , 22 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1910 */{ 0 , 2 , 10 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1911 */{ 6 , 1 , 30 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1912 */{ 0 , 2 , 18 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1913 */{ 0 , 2 , 6 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1914 */{ 5 , 1 , 26 , 55624 },/* 30 30 29 30 30 29 29 30 29 30 29 29 30 384
+1915 */{ 0 , 2 , 14 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1916 */{ 0 , 2 , 4 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1917 */{ 2 , 1 , 23 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1918 */{ 0 , 2 , 11 , 38352 },/* 30 29 29 30 29 30 29 30 30 30 29 30 0 355
+1919 */{ 7 , 2 , 1 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+1920 */{ 0 , 2 , 20 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1921 */{ 0 , 2 , 8 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1922 */{ 5 , 1 , 28 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1923 */{ 0 , 2 , 16 , 27280 },/* 29 30 30 29 30 29 30 29 30 29 29 30 0 354
+1924 */{ 0 , 2 , 5 , 44352 },/* 30 29 30 29 30 30 29 30 29 30 29 29 0 354
+1925 */{ 4 , 1 , 24 , 46504 },/* 30 29 30 30 29 30 29 30 30 29 30 29 30 385
+1926 */{ 0 , 2 , 13 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1927 */{ 0 , 2 , 2 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1928 */{ 2 , 1 , 23 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1929 */{ 0 , 2 , 10 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1930 */{ 6 , 1 , 30 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1931 */{ 0 , 2 , 17 , 58528 },/* 30 30 30 29 29 30 29 29 30 29 30 29 0 354
+1932 */{ 0 , 2 , 6 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1933 */{ 5 , 1 , 26 , 27976 },/* 29 30 30 29 30 30 29 30 29 30 29 29 30 384
+1934 */{ 0 , 2 , 14 , 23376 },/* 29 30 29 30 30 29 30 30 29 30 29 30 0 355
+1935 */{ 0 , 2 , 4 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1936 */{ 3 , 1 , 24 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 29 384
+1937 */{ 0 , 2 , 11 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1938 */{ 7 , 1 , 31 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1939 */{ 0 , 2 , 19 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1940 */{ 0 , 2 , 8 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1941 */{ 6 , 1 , 27 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1942 */{ 0 , 2 , 15 , 46736 },/* 30 29 30 30 29 30 30 29 30 29 29 30 0 355
+1943 */{ 0 , 2 , 5 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+1944 */{ 4 , 1 , 26 , 10968 },/* 29 29 30 29 30 29 30 29 30 30 29 30 30 384
+1945 */{ 0 , 2 , 13 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1946 */{ 0 , 2 , 2 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+1947 */{ 2 , 1 , 22 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+1948 */{ 0 , 2 , 10 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1949 */{ 7 , 1 , 29 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+1950 */{ 0 , 2 , 17 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+1951 */{ 0 , 2 , 6 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1952 */{ 5 , 1 , 27 , 22184 },/* 29 30 29 30 29 30 30 29 30 29 30 29 30 384
+1953 */{ 0 , 2 , 14 , 19888 },/* 29 30 29 29 30 30 29 30 30 29 30 30 0 355
+1954 */{ 0 , 2 , 4 , 9648 },/* 29 29 30 29 29 30 29 30 30 29 30 30 0 354
+1955 */{ 3 , 1 , 24 , 37560 },/* 30 29 29 30 29 29 30 29 30 29 30 30 30 384
+1956 */{ 0 , 2 , 12 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1957 */{ 8 , 1 , 31 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+1958 */{ 0 , 2 , 19 , 26960 },/* 29 30 30 29 30 29 29 30 29 30 29 30 0 354
+1959 */{ 0 , 2 , 8 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1960 */{ 6 , 1 , 28 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1961 */{ 0 , 2 , 15 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1962 */{ 0 , 2 , 5 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1963 */{ 4 , 1 , 25 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1964 */{ 0 , 2 , 13 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1965 */{ 0 , 2 , 2 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 0 354
+1966 */{ 3 , 1 , 22 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 29 383
+1967 */{ 0 , 2 , 9 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1968 */{ 7 , 1 , 30 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1969 */{ 0 , 2 , 17 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1970 */{ 0 , 2 , 6 , 39632 },/* 30 29 29 30 30 29 30 29 30 30 29 30 0 355
+1971 */{ 5 , 1 , 27 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1972 */{ 0 , 2 , 15 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1973 */{ 0 , 2 , 3 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+1974 */{ 4 , 1 , 23 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1975 */{ 0 , 2 , 11 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1976 */{ 8 , 1 , 31 , 54600 },/* 30 30 29 30 29 30 29 30 29 30 29 29 30 384
+1977 */{ 0 , 2 , 18 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1978 */{ 0 , 2 , 7 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 0 355
+1979 */{ 6 , 1 , 28 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1980 */{ 0 , 2 , 16 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1981 */{ 0 , 2 , 5 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1982 */{ 4 , 1 , 25 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1983 */{ 0 , 2 , 13 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1984 */{ 10 , 2 , 2 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1985 */{ 0 , 2 , 20 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1986 */{ 0 , 2 , 9 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1987 */{ 6 , 1 , 29 , 46504 },/* 30 29 30 30 29 30 29 30 30 29 30 29 30 385
+1988 */{ 0 , 2 , 18 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1989 */{ 0 , 2 , 6 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1990 */{ 5 , 1 , 27 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1991 */{ 0 , 2 , 15 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1992 */{ 0 , 2 , 4 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1993 */{ 3 , 1 , 23 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1994 */{ 0 , 2 , 10 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1995 */{ 8 , 1 , 31 , 27976 },/* 29 30 30 29 30 30 29 30 29 30 29 29 30 384
+1996 */{ 0 , 2 , 19 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1997 */{ 0 , 2 , 8 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1998 */{ 5 , 1 , 28 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1999 */{ 0 , 2 , 16 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2000 */{ 0 , 2 , 5 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2001 */{ 4 , 1 , 24 , 58536 },/* 30 30 30 29 29 30 29 29 30 29 30 29 30 384
+2002 */{ 0 , 2 , 12 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2003 */{ 0 , 2 , 1 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2004 */{ 2 , 1 , 22 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2005 */{ 0 , 2 , 9 , 22208 },/* 29 30 29 30 29 30 30 29 30 30 29 29 0 354
+2006 */{ 7 , 1 , 29 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+2007 */{ 0 , 2 , 18 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+2008 */{ 0 , 2 , 7 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+2009 */{ 5 , 1 , 26 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+2010 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2011 */{ 0 , 2 , 3 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2012 */{ 3 , 1 , 23 , 47696 },/* 30 29 30 30 30 29 30 29 29 30 29 30 29 384
+2013 */{ 0 , 2 , 10 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+2014 */{ 9 , 1 , 31 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2015 */{ 0 , 2 , 19 , 19360 },/* 29 30 29 29 30 29 30 30 30 29 30 29 0 354
+2016 */{ 0 , 2 , 8 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2017 */{ 5 , 1 , 28 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+2018 */{ 0 , 2 , 16 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2019 */{ 0 , 2 , 5 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2020 */{ 4 , 1 , 25 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+2021 */{ 0 , 2 , 12 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2022 */{ 0 , 2 , 1 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2023 */{ 2 , 1 , 22 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2024 */{ 0 , 2 , 10 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2025 */{ 6 , 1 , 29 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+2026 */{ 0 , 2 , 17 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+2027 */{ 0 , 2 , 7 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 0 354
+2028 */{ 5 , 1 , 27 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 29 383
+2029 */{ 0 , 2 , 13 , 55600 },/* 30 30 29 30 30 29 29 30 29 29 30 30 0 355
+2030 */{ 0 , 2 , 3 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+2031 */{ 3 , 1 , 23 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 29 384
+2032 */{ 0 , 2 , 11 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2033 */{ 11 , 1 , 31 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+2034 */{ 0 , 2 , 19 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+2035 */{ 0 , 2 , 8 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2036 */{ 6 , 1 , 28 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+2037 */{ 0 , 2 , 15 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+2038 */{ 0 , 2 , 4 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2039 */{ 5 , 1 , 24 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 29 384
+2040 */{ 0 , 2 , 12 , 46752 },/* 30 29 30 30 29 30 30 29 30 29 30 29 0 355
+2041 */{ 0 , 2 , 1 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2042 */{ 2 , 1 , 22 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+2043 */{ 0 , 2 , 10 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+2044 */{ 7 , 1 , 30 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+2045 */{ 0 , 2 , 17 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+2046 */{ 0 , 2 , 6 , 45648 },/* 30 29 30 30 29 29 30 29 29 30 29 30 0 354
+2047 */{ 5 , 1 , 26 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+2048 */{ 0 , 2 , 14 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+2049 */{ 0 , 2 , 2 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+2050 */{ 3 , 1 , 23 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 29 384
+ */};
+
+
+ internal override int MinCalendarYear
+ {
+ get
+ {
+ return (MIN_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override int MaxCalendarYear
+ {
+ get
+ {
+ return (MAX_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override DateTime MinDate
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ internal override DateTime MaxDate
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ internal override EraInfo[] CalEraInfo
+ {
+ get
+ {
+ return null;
+ }
+ }
+
+ internal override int GetYearInfo(int LunarYear, int Index)
+ {
+ if ((LunarYear < MIN_LUNISOLAR_YEAR) || (LunarYear > MAX_LUNISOLAR_YEAR))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MIN_LUNISOLAR_YEAR,
+ MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+ return s_yinfo[LunarYear - MIN_LUNISOLAR_YEAR, Index];
+ }
+
+ internal override int GetYear(int year, DateTime time)
+ {
+ return year;
+ }
+
+ internal override int GetGregorianYear(int year, int era)
+ {
+ if (era != CurrentEra && era != GregorianEra)
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+
+ if (year < MIN_LUNISOLAR_YEAR || year > MAX_LUNISOLAR_YEAR)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, MIN_LUNISOLAR_YEAR, MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return year;
+ }
+
+ public KoreanLunisolarCalendar()
+ {
+ }
+
+ public override int GetEra(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return (GregorianEra);
+ }
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ return (CalendarId.KOREA);
+ }
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.KOREANLUNISOLAR);
+ }
+ }
+
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { GregorianEra });
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs b/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs
new file mode 100644
index 0000000000..6a25eb2c4d
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs
@@ -0,0 +1,819 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace System.Globalization
+{
+ //
+ // Property Default Description
+ // PositiveSign '+' Character used to indicate positive values.
+ // NegativeSign '-' Character used to indicate negative values.
+ // NumberDecimalSeparator '.' The character used as the decimal separator.
+ // NumberGroupSeparator ',' The character used to separate groups of
+ // digits to the left of the decimal point.
+ // NumberDecimalDigits 2 The default number of decimal places.
+ // NumberGroupSizes 3 The number of digits in each group to the
+ // left of the decimal point.
+ // NaNSymbol "NaN" The string used to represent NaN values.
+ // PositiveInfinitySymbol"Infinity" The string used to represent positive
+ // infinities.
+ // NegativeInfinitySymbol"-Infinity" The string used to represent negative
+ // infinities.
+ //
+ //
+ //
+ // Property Default Description
+ // CurrencyDecimalSeparator '.' The character used as the decimal
+ // separator.
+ // CurrencyGroupSeparator ',' The character used to separate groups
+ // of digits to the left of the decimal
+ // point.
+ // CurrencyDecimalDigits 2 The default number of decimal places.
+ // CurrencyGroupSizes 3 The number of digits in each group to
+ // the left of the decimal point.
+ // CurrencyPositivePattern 0 The format of positive values.
+ // CurrencyNegativePattern 0 The format of negative values.
+ // CurrencySymbol "$" String used as local monetary symbol.
+ //
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ sealed public partial class NumberFormatInfo : IFormatProvider, ICloneable
+ {
+ // invariantInfo is constant irrespective of your current culture.
+ private static volatile NumberFormatInfo s_invariantInfo;
+
+ // READTHIS READTHIS READTHIS
+ // This class has an exact mapping onto a native structure defined in COMNumber.cpp
+ // DO NOT UPDATE THIS WITHOUT UPDATING THAT STRUCTURE. IF YOU ADD BOOL, ADD THEM AT THE END.
+ // ALSO MAKE SURE TO UPDATE mscorlib.h in the VM directory to check field offsets.
+ // READTHIS READTHIS READTHIS
+ internal int[] numberGroupSizes = new int[] { 3 };
+ internal int[] currencyGroupSizes = new int[] { 3 };
+ internal int[] percentGroupSizes = new int[] { 3 };
+ internal String positiveSign = "+";
+ internal String negativeSign = "-";
+ internal String numberDecimalSeparator = ".";
+ internal String numberGroupSeparator = ",";
+ internal String currencyGroupSeparator = ",";
+ internal String currencyDecimalSeparator = ".";
+ internal String currencySymbol = "$"; // TODO: CoreFX #846 Restore to the original value "\x00a4"; // U+00a4 is the symbol for International Monetary Fund.
+ internal String nanSymbol = "NaN";
+ internal String positiveInfinitySymbol = "Infinity";
+ internal String negativeInfinitySymbol = "-Infinity";
+ internal String percentDecimalSeparator = ".";
+ internal String percentGroupSeparator = ",";
+ internal String percentSymbol = "%";
+ internal String perMilleSymbol = "\u2030";
+
+
+ [OptionalField(VersionAdded = 2)]
+ internal String[] nativeDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+ internal int numberDecimalDigits = 2;
+ internal int currencyDecimalDigits = 2;
+ internal int currencyPositivePattern = 0;
+ internal int currencyNegativePattern = 0;
+ internal int numberNegativePattern = 1;
+ internal int percentPositivePattern = 0;
+ internal int percentNegativePattern = 0;
+ internal int percentDecimalDigits = 2;
+
+
+ internal bool isReadOnly = false;
+
+ // Is this NumberFormatInfo for invariant culture?
+
+ [OptionalField(VersionAdded = 2)]
+ internal bool m_isInvariant = false;
+
+ public NumberFormatInfo() : this(null)
+ {
+ }
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx) { }
+
+ [OnDeserializing]
+ private void OnDeserializing(StreamingContext ctx) { }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx) { }
+
+ private static void VerifyDecimalSeparator(String decSep, String propertyName)
+ {
+ if (decSep == null)
+ {
+ throw new ArgumentNullException(propertyName,
+ SR.ArgumentNull_String);
+ }
+
+ if (decSep.Length == 0)
+ {
+ throw new ArgumentException(SR.Argument_EmptyDecString);
+ }
+ Contract.EndContractBlock();
+ }
+
+ private static void VerifyGroupSeparator(String groupSep, String propertyName)
+ {
+ if (groupSep == null)
+ {
+ throw new ArgumentNullException(propertyName,
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ }
+
+
+ internal NumberFormatInfo(CultureData cultureData)
+ {
+ if (cultureData != null)
+ {
+ // We directly use fields here since these data is coming from data table or Win32, so we
+ // don't need to verify their values (except for invalid parsing situations).
+ cultureData.GetNFIValues(this);
+
+ if (cultureData.IsInvariantCulture)
+ {
+ // For invariant culture
+ this.m_isInvariant = true;
+ }
+ }
+ }
+
+ [Pure]
+ private void VerifyWritable()
+ {
+ if (isReadOnly)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+ Contract.EndContractBlock();
+ }
+
+ // Returns a default NumberFormatInfo that will be universally
+ // supported and constant irrespective of the current culture.
+ // Used by FromString methods.
+ //
+
+ public static NumberFormatInfo InvariantInfo
+ {
+ get
+ {
+ if (s_invariantInfo == null)
+ {
+ // Lazy create the invariant info. This cannot be done in a .cctor because exceptions can
+ // be thrown out of a .cctor stack that will need this.
+ NumberFormatInfo nfi = new NumberFormatInfo();
+ nfi.m_isInvariant = true;
+ s_invariantInfo = ReadOnly(nfi);
+ }
+ return s_invariantInfo;
+ }
+ }
+
+ public static NumberFormatInfo GetInstance(IFormatProvider formatProvider)
+ {
+ // Fast case for a regular CultureInfo
+ NumberFormatInfo info;
+ CultureInfo cultureProvider = formatProvider as CultureInfo;
+ if (cultureProvider != null && !cultureProvider.m_isInherited)
+ {
+ info = cultureProvider.numInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ else
+ {
+ return cultureProvider.NumberFormat;
+ }
+ }
+ // Fast case for an NFI;
+ info = formatProvider as NumberFormatInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ if (formatProvider != null)
+ {
+ info = formatProvider.GetFormat(typeof(NumberFormatInfo)) as NumberFormatInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ }
+ return CurrentInfo;
+ }
+
+
+
+ public Object Clone()
+ {
+ NumberFormatInfo n = (NumberFormatInfo)MemberwiseClone();
+ n.isReadOnly = false;
+ return n;
+ }
+
+
+ public int CurrencyDecimalDigits
+ {
+ get { return currencyDecimalDigits; }
+ set
+ {
+ if (value < 0 || value > 99)
+ {
+ throw new ArgumentOutOfRangeException(
+ "CurrencyDecimalDigits",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 99));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ currencyDecimalDigits = value;
+ }
+ }
+
+
+ public String CurrencyDecimalSeparator
+ {
+ get { return currencyDecimalSeparator; }
+ set
+ {
+ VerifyWritable();
+ VerifyDecimalSeparator(value, "CurrencyDecimalSeparator");
+ currencyDecimalSeparator = value;
+ }
+ }
+
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return isReadOnly;
+ }
+ }
+
+ //
+ // Check the values of the groupSize array.
+ //
+ // Every element in the groupSize array should be between 1 and 9
+ // excpet the last element could be zero.
+ //
+ internal static void CheckGroupSize(String propName, int[] groupSize)
+ {
+ for (int i = 0; i < groupSize.Length; i++)
+ {
+ if (groupSize[i] < 1)
+ {
+ if (i == groupSize.Length - 1 && groupSize[i] == 0)
+ return;
+ throw new ArgumentException(SR.Argument_InvalidGroupSize, propName);
+ }
+ else if (groupSize[i] > 9)
+ {
+ throw new ArgumentException(SR.Argument_InvalidGroupSize, propName);
+ }
+ }
+ }
+
+
+ public int[] CurrencyGroupSizes
+ {
+ get
+ {
+ return ((int[])currencyGroupSizes.Clone());
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("CurrencyGroupSizes",
+ SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+
+ Int32[] inputSizes = (Int32[])value.Clone();
+ CheckGroupSize("CurrencyGroupSizes", inputSizes);
+ currencyGroupSizes = inputSizes;
+ }
+ }
+
+
+
+ public int[] NumberGroupSizes
+ {
+ get
+ {
+ return ((int[])numberGroupSizes.Clone());
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("NumberGroupSizes",
+ SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+
+ Int32[] inputSizes = (Int32[])value.Clone();
+ CheckGroupSize("NumberGroupSizes", inputSizes);
+ numberGroupSizes = inputSizes;
+ }
+ }
+
+
+ public int[] PercentGroupSizes
+ {
+ get
+ {
+ return ((int[])percentGroupSizes.Clone());
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("PercentGroupSizes",
+ SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ Int32[] inputSizes = (Int32[])value.Clone();
+ CheckGroupSize("PercentGroupSizes", inputSizes);
+ percentGroupSizes = inputSizes;
+ }
+ }
+
+
+ public String CurrencyGroupSeparator
+ {
+ get { return currencyGroupSeparator; }
+ set
+ {
+ VerifyWritable();
+ VerifyGroupSeparator(value, "CurrencyGroupSeparator");
+ currencyGroupSeparator = value;
+ }
+ }
+
+
+ public String CurrencySymbol
+ {
+ get { return currencySymbol; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("CurrencySymbol",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ currencySymbol = value;
+ }
+ }
+
+ // Returns the current culture's NumberFormatInfo. Used by Parse methods.
+ //
+
+ public static NumberFormatInfo CurrentInfo
+ {
+ get
+ {
+ System.Globalization.CultureInfo culture = CultureInfo.CurrentCulture;
+ if (!culture.m_isInherited)
+ {
+ NumberFormatInfo info = culture.numInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ }
+ return ((NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo)));
+ }
+ }
+
+
+ public String NaNSymbol
+ {
+ get
+ {
+ return nanSymbol;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("NaNSymbol",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ nanSymbol = value;
+ }
+ }
+
+
+
+ public int CurrencyNegativePattern
+ {
+ get { return currencyNegativePattern; }
+ set
+ {
+ if (value < 0 || value > 15)
+ {
+ throw new ArgumentOutOfRangeException(
+ "CurrencyNegativePattern",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 15));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ currencyNegativePattern = value;
+ }
+ }
+
+
+ public int NumberNegativePattern
+ {
+ get { return numberNegativePattern; }
+ set
+ {
+ //
+ // NOTENOTE: the range of value should correspond to negNumberFormats[] in vm\COMNumber.cpp.
+ //
+ if (value < 0 || value > 4)
+ {
+ throw new ArgumentOutOfRangeException(
+ "NumberNegativePattern",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 4));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ numberNegativePattern = value;
+ }
+ }
+
+
+ public int PercentPositivePattern
+ {
+ get { return percentPositivePattern; }
+ set
+ {
+ //
+ // NOTENOTE: the range of value should correspond to posPercentFormats[] in vm\COMNumber.cpp.
+ //
+ if (value < 0 || value > 3)
+ {
+ throw new ArgumentOutOfRangeException(
+ "PercentPositivePattern",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 3));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ percentPositivePattern = value;
+ }
+ }
+
+
+ public int PercentNegativePattern
+ {
+ get { return percentNegativePattern; }
+ set
+ {
+ //
+ // NOTENOTE: the range of value should correspond to posPercentFormats[] in vm\COMNumber.cpp.
+ //
+ if (value < 0 || value > 11)
+ {
+ throw new ArgumentOutOfRangeException(
+ "PercentNegativePattern",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 11));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ percentNegativePattern = value;
+ }
+ }
+
+
+ public String NegativeInfinitySymbol
+ {
+ get
+ {
+ return negativeInfinitySymbol;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("NegativeInfinitySymbol",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ negativeInfinitySymbol = value;
+ }
+ }
+
+
+ public String NegativeSign
+ {
+ get { return negativeSign; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("NegativeSign",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ negativeSign = value;
+ }
+ }
+
+
+ public int NumberDecimalDigits
+ {
+ get { return numberDecimalDigits; }
+ set
+ {
+ if (value < 0 || value > 99)
+ {
+ throw new ArgumentOutOfRangeException(
+ "NumberDecimalDigits",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 99));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ numberDecimalDigits = value;
+ }
+ }
+
+
+ public String NumberDecimalSeparator
+ {
+ get { return numberDecimalSeparator; }
+ set
+ {
+ VerifyWritable();
+ VerifyDecimalSeparator(value, "NumberDecimalSeparator");
+ numberDecimalSeparator = value;
+ }
+ }
+
+
+ public String NumberGroupSeparator
+ {
+ get { return numberGroupSeparator; }
+ set
+ {
+ VerifyWritable();
+ VerifyGroupSeparator(value, "NumberGroupSeparator");
+ numberGroupSeparator = value;
+ }
+ }
+
+
+ public int CurrencyPositivePattern
+ {
+ get { return currencyPositivePattern; }
+ set
+ {
+ if (value < 0 || value > 3)
+ {
+ throw new ArgumentOutOfRangeException(
+ "CurrencyPositivePattern",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 3));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ currencyPositivePattern = value;
+ }
+ }
+
+
+ public String PositiveInfinitySymbol
+ {
+ get
+ {
+ return positiveInfinitySymbol;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("PositiveInfinitySymbol",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ positiveInfinitySymbol = value;
+ }
+ }
+
+
+ public String PositiveSign
+ {
+ get { return positiveSign; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("PositiveSign",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ positiveSign = value;
+ }
+ }
+
+
+ public int PercentDecimalDigits
+ {
+ get { return percentDecimalDigits; }
+ set
+ {
+ if (value < 0 || value > 99)
+ {
+ throw new ArgumentOutOfRangeException(
+ "PercentDecimalDigits",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 0,
+ 99));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ percentDecimalDigits = value;
+ }
+ }
+
+
+ public String PercentDecimalSeparator
+ {
+ get { return percentDecimalSeparator; }
+ set
+ {
+ VerifyWritable();
+ VerifyDecimalSeparator(value, "PercentDecimalSeparator");
+ percentDecimalSeparator = value;
+ }
+ }
+
+
+ public String PercentGroupSeparator
+ {
+ get { return percentGroupSeparator; }
+ set
+ {
+ VerifyWritable();
+ VerifyGroupSeparator(value, "PercentGroupSeparator");
+ percentGroupSeparator = value;
+ }
+ }
+
+
+ public String PercentSymbol
+ {
+ get
+ {
+ return percentSymbol;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("PercentSymbol",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ percentSymbol = value;
+ }
+ }
+
+
+ public String PerMilleSymbol
+ {
+ get { return perMilleSymbol; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("PerMilleSymbol",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ perMilleSymbol = value;
+ }
+ }
+
+ public Object GetFormat(Type formatType)
+ {
+ return formatType == typeof(NumberFormatInfo) ? this : null;
+ }
+
+ public static NumberFormatInfo ReadOnly(NumberFormatInfo nfi)
+ {
+ if (nfi == null)
+ {
+ throw new ArgumentNullException("nfi");
+ }
+ Contract.EndContractBlock();
+ if (nfi.IsReadOnly)
+ {
+ return (nfi);
+ }
+ NumberFormatInfo info = (NumberFormatInfo)(nfi.MemberwiseClone());
+ info.isReadOnly = true;
+ return info;
+ }
+
+ // private const NumberStyles InvalidNumberStyles = unchecked((NumberStyles) 0xFFFFFC00);
+ private const NumberStyles InvalidNumberStyles = ~(NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite
+ | NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign
+ | NumberStyles.AllowParentheses | NumberStyles.AllowDecimalPoint
+ | NumberStyles.AllowThousands | NumberStyles.AllowExponent
+ | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier);
+
+ internal static void ValidateParseStyleInteger(NumberStyles style)
+ {
+ // Check for undefined flags
+ if ((style & InvalidNumberStyles) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidNumberStyles, "style");
+ }
+ Contract.EndContractBlock();
+ if ((style & NumberStyles.AllowHexSpecifier) != 0)
+ { // Check for hex number
+ if ((style & ~NumberStyles.HexNumber) != 0)
+ {
+ throw new ArgumentException(SR.Arg_InvalidHexStyle);
+ }
+ }
+ }
+
+ internal static void ValidateParseStyleFloatingPoint(NumberStyles style)
+ {
+ // Check for undefined flags
+ if ((style & InvalidNumberStyles) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidNumberStyles, "style");
+ }
+ Contract.EndContractBlock();
+ if ((style & NumberStyles.AllowHexSpecifier) != 0)
+ { // Check for hex number
+ throw new ArgumentException(SR.Arg_HexStyleNotSupported);
+ }
+ }
+ } // NumberFormatInfo
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/mscorlib/corefx/System/Globalization/PersianCalendar.cs b/src/mscorlib/corefx/System/Globalization/PersianCalendar.cs
new file mode 100644
index 0000000000..57bef7eee1
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/PersianCalendar.cs
@@ -0,0 +1,613 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about PersianCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ // Modern Persian calendar is a solar observation based calendar. Each new year begins on the day when the vernal equinox occurs before noon.
+ // The epoch is the date of the vernal equinox prior to the epoch of the Islamic calendar (March 19, 622 Julian or March 22, 622 Gregorian)
+
+ // There is no Persian year 0. Ordinary years have 365 days. Leap years have 366 days with the last month (Esfand) gaining the extra day.
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 0622/03/22 9999/12/31
+ ** Persian 0001/01/01 9378/10/13
+ */
+
+ [Serializable]
+ public class PersianCalendar : Calendar
+ {
+ public static readonly int PersianEra = 1;
+
+ internal static long PersianEpoch = new DateTime(622, 3, 22).Ticks / GregorianCalendar.TicksPerDay;
+ private const int ApproximateHalfYear = 180;
+
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+ internal const int MonthsPerYear = 12;
+
+ internal static int[] DaysToMonth = { 0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336, 366 };
+
+ internal const int MaxCalendarYear = 9378;
+ internal const int MaxCalendarMonth = 10;
+ internal const int MaxCalendarDay = 13;
+
+ // Persian calendar (year: 1, month: 1, day:1 ) = Gregorian (year: 622, month: 3, day: 22)
+ // This is the minimal Gregorian date that we support in the PersianCalendar.
+ internal static DateTime minDate = new DateTime(622, 3, 22);
+ internal static DateTime maxDate = DateTime.MaxValue;
+
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ // Return the type of the Persian calendar.
+ //
+
+
+ //public override CalendarAlgorithmType AlgorithmType {
+ // get {
+ // return CalendarAlgorithmType.SolarCalendar;
+ // }
+ //}
+
+ // Construct an instance of Persian calendar.
+
+ public PersianCalendar()
+ {
+ }
+
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ return CalendarId.GREGORIAN;
+ }
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return CalendarId.PERSIAN;
+ }
+ }
+
+
+ /*=================================GetAbsoluteDatePersian==========================
+ **Action: Gets the Absolute date for the given Persian date. The absolute date means
+ ** the number of days from January 1st, 1 A.D.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+ private long GetAbsoluteDatePersian(int year, int month, int day)
+ {
+ if (year >= 1 && year <= MaxCalendarYear && month >= 1 && month <= 12)
+ {
+ int ordinalDay = DaysInPreviousMonths(month) + day - 1; // day is one based, make 0 based since this will be the number of days we add to beginning of year below
+ int approximateDaysFromEpochForYearStart = (int)(CalendricalCalculationsHelper.MeanTropicalYearInDays * (year - 1));
+ long yearStart = CalendricalCalculationsHelper.PersianNewYearOnOrBefore(PersianEpoch + approximateDaysFromEpochForYearStart + ApproximateHalfYear);
+ yearStart += ordinalDay;
+ return yearStart;
+ }
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+
+ internal static void CheckTicksRange(long ticks)
+ {
+ if (ticks < minDate.Ticks || ticks > maxDate.Ticks)
+ {
+ throw new ArgumentOutOfRangeException(
+ "time",
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.ArgumentOutOfRange_CalendarRange,
+ minDate,
+ maxDate));
+ }
+ }
+
+ internal static void CheckEraRange(int era)
+ {
+ if (era != CurrentEra && era != PersianEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ }
+
+ internal static void CheckYearRange(int year, int era)
+ {
+ CheckEraRange(era);
+ if (year < 1 || year > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxCalendarYear));
+ }
+ }
+
+ internal static void CheckYearMonthRange(int year, int month, int era)
+ {
+ CheckYearRange(year, era);
+ if (year == MaxCalendarYear)
+ {
+ if (month > MaxCalendarMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxCalendarMonth));
+ }
+ }
+
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ }
+
+ private static int MonthFromOrdinalDay(int ordinalDay)
+ {
+ Contract.Assert(ordinalDay <= 366);
+ int index = 0;
+ while (ordinalDay > DaysToMonth[index])
+ index++;
+
+ return index;
+ }
+
+ private static int DaysInPreviousMonths(int month)
+ {
+ Contract.Assert(1 <= month && month <= 12);
+ --month; // months are one based but for calculations use 0 based
+ return DaysToMonth[month];
+ }
+
+ /*=================================GetDatePart==========================
+ **Action: Returns a given date part of this <i>DateTime</i>. This method is used
+ ** to compute the year, day-of-year, month, or day part.
+ **Returns:
+ **Arguments:
+ **Exceptions: ArgumentException if part is incorrect.
+ ============================================================================*/
+
+ internal int GetDatePart(long ticks, int part)
+ {
+ long NumDays; // The calculation buffer in number of days.
+
+ CheckTicksRange(ticks);
+
+ //
+ // Get the absolute date. The absolute date is the number of days from January 1st, 1 A.D.
+ // 1/1/0001 is absolute date 1.
+ //
+ NumDays = ticks / GregorianCalendar.TicksPerDay + 1;
+
+ //
+ // Calculate the appromixate Persian Year.
+ //
+
+ long yearStart = CalendricalCalculationsHelper.PersianNewYearOnOrBefore(NumDays);
+ int y = (int)(Math.Floor(((yearStart - PersianEpoch) / CalendricalCalculationsHelper.MeanTropicalYearInDays) + 0.5)) + 1;
+ Contract.Assert(y >= 1);
+
+ if (part == DatePartYear)
+ {
+ return y;
+ }
+
+ //
+ // Calculate the Persian Month.
+ //
+
+ int ordinalDay = (int)(NumDays - CalendricalCalculationsHelper.GetNumberOfDays(this.ToDateTime(y, 1, 1, 0, 0, 0, 0, 1)));
+
+ if (part == DatePartDayOfYear)
+ {
+ return ordinalDay;
+ }
+
+ int m = MonthFromOrdinalDay(ordinalDay);
+ Contract.Assert(ordinalDay >= 1);
+ Contract.Assert(m >= 1 && m <= 12);
+ if (part == DatePartMonth)
+ {
+ return m;
+ }
+
+ int d = ordinalDay - DaysInPreviousMonths(m);
+ Contract.Assert(1 <= d);
+ Contract.Assert(d <= 31);
+
+ //
+ // Calculate the Persian Day.
+ //
+
+ if (part == DatePartDay)
+ {
+ return (d);
+ }
+
+ // Incorrect part value.
+ throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing);
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ -120000,
+ 120000));
+ }
+ Contract.EndContractBlock();
+ // Get the date in Persian calendar.
+ int y = GetDatePart(time.Ticks, DatePartYear);
+ int m = GetDatePart(time.Ticks, DatePartMonth);
+ int d = GetDatePart(time.Ticks, DatePartDay);
+ int i = m - 1 + months;
+ if (i >= 0)
+ {
+ m = i % 12 + 1;
+ y = y + i / 12;
+ }
+ else
+ {
+ m = 12 + (i + 1) % 12;
+ y = y + (i - 11) / 12;
+ }
+ int days = GetDaysInMonth(y, m);
+ if (d > days)
+ {
+ d = days;
+ }
+ long ticks = GetAbsoluteDatePersian(y, m, d) * TicksPerDay + time.Ticks % TicksPerDay;
+ Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (AddMonths(time, years * 12));
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDay));
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartDayOfYear));
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ CheckYearMonthRange(year, month, era);
+
+ if ((month == MaxCalendarMonth) && (year == MaxCalendarYear))
+ {
+ return MaxCalendarDay;
+ }
+
+ int daysInMonth = DaysToMonth[month] - DaysToMonth[month - 1];
+ if ((month == MonthsPerYear) && !IsLeapYear(year))
+ {
+ Contract.Assert(daysInMonth == 30);
+ --daysInMonth;
+ }
+ return daysInMonth;
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ if (year == MaxCalendarYear)
+ {
+ return DaysToMonth[MaxCalendarMonth - 1] + MaxCalendarDay;
+ }
+ // Common years have 365 days. Leap years have 366 days.
+ return (IsLeapYear(year, CurrentEra) ? 366 : 365);
+ }
+
+ // Returns the era for the specified DateTime value.
+
+
+ public override int GetEra(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return (PersianEra);
+ }
+
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { PersianEra });
+ }
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+
+ public override int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartMonth));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ if (year == MaxCalendarYear)
+ {
+ return MaxCalendarMonth;
+ }
+ return (12);
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and MaxCalendarYear.
+ //
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (GetDatePart(time.Ticks, DatePartYear));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ // The year/month/era value checking is done in GetDaysInMonth().
+ int daysInMonth = GetDaysInMonth(year, month, era);
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Day,
+ daysInMonth,
+ month));
+ }
+ return (IsLeapYear(year, era) && month == 12 && day == 30);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+
+ public override int GetLeapMonth(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return (0);
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ CheckYearMonthRange(year, month, era);
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+
+ if (year == MaxCalendarYear)
+ {
+ return false;
+ }
+
+ return (GetAbsoluteDatePersian(year + 1, 1, 1) - GetAbsoluteDatePersian(year, 1, 1)) == 366;
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ // The year/month/era checking is done in GetDaysInMonth().
+ int daysInMonth = GetDaysInMonth(year, month, era);
+ if (day < 1 || day > daysInMonth)
+ {
+ // BCLDebug.Log("year = " + year + ", month = " + month + ", day = " + day);
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Day,
+ daysInMonth,
+ month));
+ }
+
+ long lDate = GetAbsoluteDatePersian(year, month, day);
+
+ if (lDate >= 0)
+ {
+ return (new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond)));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 1410;
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "value",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ MaxCalendarYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year < 100)
+ {
+ return (base.ToFourDigitYear(year));
+ }
+
+ if (year > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ MaxCalendarYear));
+ }
+ return (year);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/RegionInfo.cs b/src/mscorlib/corefx/System/Globalization/RegionInfo.cs
new file mode 100644
index 0000000000..0669349040
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/RegionInfo.cs
@@ -0,0 +1,324 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+// Purpose: This class represents settings specified by de jure or
+// de facto standards for a particular country/region. In
+// contrast to CultureInfo, the RegionInfo does not represent
+// preferences of the user and does not depend on the user's
+// language or culture.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class RegionInfo
+ {
+ //--------------------------------------------------------------------//
+ // Internal Information //
+ //--------------------------------------------------------------------//
+
+ //
+ // Variables.
+ //
+
+ //
+ // Name of this region (ie: es-US): serialized, the field used for deserialization
+ //
+ internal String _name;
+
+ //
+ // The CultureData instance that we are going to read data from.
+ //
+ internal CultureData _cultureData;
+
+ //
+ // The RegionInfo for our current region
+ //
+ internal static volatile RegionInfo s_currentRegionInfo;
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // RegionInfo Constructors
+ //
+ // Note: We prefer that a region be created with a full culture name (ie: en-US)
+ // because otherwise the native strings won't be right.
+ //
+ // In Silverlight we enforce that RegionInfos must be created with a full culture name
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public RegionInfo(String name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ if (name.Length == 0) //The InvariantCulture has no matching region
+ {
+ throw new ArgumentException(SR.Argument_NoRegionInvariantCulture, "name");
+ }
+
+ Contract.EndContractBlock();
+
+ //
+ // For CoreCLR we only want the region names that are full culture names
+ //
+ _cultureData = CultureData.GetCultureDataForRegion(name, true);
+ if (_cultureData == null)
+ throw new ArgumentException(
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.Argument_InvalidCultureName, name), "name");
+
+
+ // Not supposed to be neutral
+ if (_cultureData.IsNeutralCulture)
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidNeutralRegionName, name), "name");
+
+ SetName(name);
+ }
+
+ internal RegionInfo(CultureData cultureData)
+ {
+ _cultureData = cultureData;
+ _name = _cultureData.SREGIONNAME;
+ }
+
+ private void SetName(string name)
+ {
+ // Use the name of the region we found
+ _name = _cultureData.SREGIONNAME;
+ }
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx) { }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ _cultureData = CultureData.GetCultureData(_name, true);
+
+ if (_cultureData == null)
+ {
+ throw new ArgumentException(
+ String.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidCultureName, _name),
+ "_name");
+ }
+
+ _name = _cultureData.SREGIONNAME;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetCurrentRegion
+ //
+ // This instance provides methods based on the current user settings.
+ // These settings are volatile and may change over the lifetime of the
+ // thread.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public static RegionInfo CurrentRegion
+ {
+ get
+ {
+ RegionInfo temp = s_currentRegionInfo;
+ if (temp == null)
+ {
+ temp = new RegionInfo(CultureInfo.CurrentCulture.m_cultureData);
+
+ // Need full name for custom cultures
+ temp._name = temp._cultureData.SREGIONNAME;
+ s_currentRegionInfo = temp;
+ }
+ return temp;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetName
+ //
+ // Returns the name of the region (ie: en-US)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String Name
+ {
+ get
+ {
+ Contract.Assert(_name != null, "Expected RegionInfo._name to be populated already");
+ return (_name);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetEnglishName
+ //
+ // Returns the name of the region in English. (ie: United States)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String EnglishName
+ {
+ get
+ {
+ return (_cultureData.SENGCOUNTRY);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetDisplayName
+ //
+ // Returns the display name (localized) of the region. (ie: United States
+ // if the current UI language is en-US)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String DisplayName
+ {
+ get
+ {
+ return (_cultureData.SLOCALIZEDCOUNTRY);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetNativeName
+ //
+ // Returns the native name of the region. (ie: Deutschland)
+ // WARNING: You need a full locale name for this to make sense.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual String NativeName
+ {
+ get
+ {
+ return (_cultureData.SNATIVECOUNTRY);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // TwoLetterISORegionName
+ //
+ // Returns the two letter ISO region name (ie: US)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String TwoLetterISORegionName
+ {
+ get
+ {
+ return (_cultureData.SISO3166CTRYNAME);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsMetric
+ //
+ // Returns true if this region uses the metric measurement system
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual bool IsMetric
+ {
+ get
+ {
+ int value = _cultureData.IMEASURE;
+ return (value == 0);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CurrencySymbol
+ //
+ // Currency Symbol for this locale, ie: Fr. or $
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String CurrencySymbol
+ {
+ get
+ {
+ return (_cultureData.SCURRENCY);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ISOCurrencySymbol
+ //
+ // ISO Currency Symbol for this locale, ie: CHF
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String ISOCurrencySymbol
+ {
+ get
+ {
+ return (_cultureData.SINTLSYMBOL);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Equals
+ //
+ // Implements Object.Equals(). Returns a boolean indicating whether
+ // or not object refers to the same RegionInfo as the current instance.
+ //
+ // RegionInfos are considered equal if and only if they have the same name
+ // (ie: en-US)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override bool Equals(Object value)
+ {
+ RegionInfo that = value as RegionInfo;
+ if (that != null)
+ {
+ return this.Name.Equals(that.Name);
+ }
+
+ return (false);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCode
+ //
+ // Implements Object.GetHashCode(). Returns the hash code for the
+ // CultureInfo. The hash code is guaranteed to be the same for RegionInfo
+ // A and B where A.Equals(B) is true.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override int GetHashCode()
+ {
+ return (this.Name.GetHashCode());
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Implements Object.ToString(). Returns the name of the Region, ie: es-US
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override String ToString()
+ {
+ return (Name);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/STUBS.cs b/src/mscorlib/corefx/System/Globalization/STUBS.cs
new file mode 100644
index 0000000000..8c85e836d6
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/STUBS.cs
@@ -0,0 +1,180 @@
+namespace System.Globalization
+{
+ public abstract partial class Calendar : System.ICloneable
+ {
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public virtual int GetLeapMonth(int year) { throw new NotImplementedException(); }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public enum CalendarAlgorithmType
+ {
+ Unknown = 0, // This is the default value to return in the Calendar base class.
+ SolarCalendar = 1, // Solar-base calendar, such as GregorianCalendar, jaoaneseCalendar, JulianCalendar, etc.
+ // Solar calendars are based on the solar year and seasons.
+ LunarCalendar = 2, // Lunar-based calendar, such as Hijri and UmAlQuraCalendar.
+ // Lunar calendars are based on the path of the moon. The seasons are not accurately represented.
+ LunisolarCalendar = 3 // Lunisolar-based calendar which use leap month rule, such as HebrewCalendar and Asian Lunisolar calendars.
+ // Lunisolar calendars are based on the cycle of the moon, but consider the seasons as a secondary consideration,
+ // so they align with the seasons as well as lunar events.
+ }
+
+ public static partial class CharUnicodeInfo
+ {
+ public static int GetDecimalDigitValue(char ch) { throw new NotImplementedException(); }
+ public static int GetDecimalDigitValue(string s, int index) { throw new NotImplementedException(); }
+ public static int GetDigitValue(char ch) { throw new NotImplementedException(); }
+ public static int GetDigitValue(string s, int index) { throw new NotImplementedException(); }
+ }
+
+ public partial class CompareInfo : System.Runtime.Serialization.IDeserializationCallback
+ {
+ public int LCID { get { throw new NotImplementedException(); } }
+ public static System.Globalization.CompareInfo GetCompareInfo(int culture) { throw new NotImplementedException(); }
+ public static System.Globalization.CompareInfo GetCompareInfo(int culture, System.Reflection.Assembly assembly) { throw new NotImplementedException(); }
+ public static System.Globalization.CompareInfo GetCompareInfo(string name, System.Reflection.Assembly assembly) { throw new NotImplementedException(); }
+ public virtual System.Globalization.SortKey GetSortKey(string source) { throw new NotImplementedException(); }
+ public virtual System.Globalization.SortKey GetSortKey(string source, System.Globalization.CompareOptions options) { throw new NotImplementedException(); }
+ public virtual int IndexOf(string source, char value, int startIndex) { throw new NotImplementedException(); }
+ public virtual int IndexOf(string source, string value, int startIndex) { throw new NotImplementedException(); }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public static bool IsSortable(char ch) { throw new NotImplementedException(); }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ [System.Security.SecuritySafeCriticalAttribute]
+ public static bool IsSortable(string text) { throw new NotImplementedException(); }
+ public virtual int LastIndexOf(string source, char value, int startIndex) { throw new NotImplementedException(); }
+ public virtual int LastIndexOf(string source, string value, int startIndex) { throw new NotImplementedException(); }
+ }
+
+ public partial class CultureInfo : System.ICloneable, System.IFormatProvider
+ {
+ public CultureInfo(int culture) { throw new NotImplementedException(); }
+ public CultureInfo(int culture, bool useUserOverride) { throw new NotImplementedException(); }
+ public static System.Globalization.CultureInfo InstalledUICulture { get { throw new NotImplementedException(); } }
+ public virtual int LCID { get { throw new NotImplementedException(); } }
+ public virtual string ThreeLetterISOLanguageName { get { throw new NotImplementedException(); } }
+ public virtual string ThreeLetterWindowsLanguageName { get { throw new NotImplementedException(); } }
+ public void ClearCachedData() { throw new NotImplementedException(); }
+ public static System.Globalization.CultureInfo CreateSpecificCulture(string name) { throw new NotImplementedException(); }
+ public static System.Globalization.CultureInfo GetCultureInfo(int culture) { throw new NotImplementedException(); }
+ public static System.Globalization.CultureInfo GetCultureInfo(string name, string altName) { throw new NotImplementedException(); }
+ public static System.Globalization.CultureInfo GetCultureInfoByIetfLanguageTag(string name) { throw new NotImplementedException(); }
+ public static System.Globalization.CultureInfo[] GetCultures(System.Globalization.CultureTypes types) { throw new NotImplementedException(); }
+ }
+
+ public partial class CultureNotFoundException : System.ArgumentException, System.Runtime.Serialization.ISerializable
+ {
+ public CultureNotFoundException(string message, int invalidCultureId, System.Exception innerException) { throw new NotImplementedException(); }
+ public CultureNotFoundException(string paramName, int invalidCultureId, string message) { throw new NotImplementedException(); }
+ public virtual System.Nullable<int> InvalidCultureId { get { throw new NotImplementedException(); } }
+ }
+
+ public enum CultureTypes
+ {
+ AllCultures = 7,
+ [System.ObsoleteAttribute("This value has been deprecated. Please use other values in CultureTypes.")]
+ FrameworkCultures = 64,
+ InstalledWin32Cultures = 4,
+ NeutralCultures = 1,
+ ReplacementCultures = 16,
+ SpecificCultures = 2,
+ UserCustomCulture = 8,
+ [System.ObsoleteAttribute("This value has been deprecated. Please use other values in CultureTypes.")]
+ WindowsOnlyCultures = 32,
+ }
+
+ public sealed partial class DateTimeFormatInfo : System.ICloneable, System.IFormatProvider
+ {
+ // Can't do partial properties so add the setter for DateSeparator and TimeSeparator
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public string NativeCalendarName { get { throw new NotImplementedException(); } }
+ public string[] GetAllDateTimePatterns() { throw new NotImplementedException(); }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public string GetShortestDayName(System.DayOfWeek dayOfWeek) { throw new NotImplementedException(); }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public void SetAllDateTimePatterns(string[] patterns, char format) { throw new NotImplementedException(); }
+ }
+
+ public enum DigitShapes
+ {
+ Context = 0,
+ NativeNational = 2,
+ None = 1,
+ }
+
+ public sealed partial class IdnMapping
+ {
+ public IdnMapping() { }
+ public bool AllowUnassigned { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
+ public bool UseStd3AsciiRules { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
+ public override bool Equals(object obj) { throw new NotImplementedException(); }
+ public string GetAscii(string unicode) { throw new NotImplementedException(); }
+ public string GetAscii(string unicode, int index) { throw new NotImplementedException(); }
+ public string GetAscii(string unicode, int index, int count) { throw new NotImplementedException(); }
+ public override int GetHashCode() { throw new NotImplementedException(); }
+ public string GetUnicode(string ascii) { throw new NotImplementedException(); }
+ public string GetUnicode(string ascii, int index) { throw new NotImplementedException(); }
+ public string GetUnicode(string ascii, int index, int count) { throw new NotImplementedException(); }
+ }
+
+ public sealed partial class NumberFormatInfo : System.ICloneable, System.IFormatProvider
+ {
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public System.Globalization.DigitShapes DigitSubstitution { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public string[] NativeDigits { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
+ }
+
+ public partial class RegionInfo
+ {
+ public RegionInfo(int culture) { throw new NotImplementedException(); }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public virtual string CurrencyEnglishName { get { throw new NotImplementedException(); } }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public virtual string CurrencyNativeName { get { throw new NotImplementedException(); } }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public virtual int GeoId { get { throw new NotImplementedException(); } }
+ public virtual string ThreeLetterISORegionName { get { throw new NotImplementedException(); } }
+ public virtual string ThreeLetterWindowsRegionName { get { throw new NotImplementedException(); } }
+ }
+
+ public partial class SortKey
+ {
+ internal SortKey() { throw new NotImplementedException(); }
+ public virtual byte[] KeyData { get { throw new NotImplementedException(); } }
+ public virtual string OriginalString { get { throw new NotImplementedException(); } }
+ public static int Compare(System.Globalization.SortKey sortkey1, System.Globalization.SortKey sortkey2) { throw new NotImplementedException(); }
+ public override bool Equals(object value) { throw new NotImplementedException(); }
+ public override int GetHashCode() { throw new NotImplementedException(); }
+ public override string ToString() { throw new NotImplementedException(); }
+ }
+
+ public sealed partial class SortVersion : System.IEquatable<System.Globalization.SortVersion>
+ {
+ public SortVersion(int fullVersion, System.Guid sortId) { throw new NotImplementedException(); }
+ public int FullVersion { get { throw new NotImplementedException(); } }
+ public System.Guid SortId { get { throw new NotImplementedException(); } }
+ public bool Equals(System.Globalization.SortVersion other) { throw new NotImplementedException(); }
+ public override bool Equals(object obj) { throw new NotImplementedException(); }
+ public override int GetHashCode() { throw new NotImplementedException(); }
+ public static bool operator ==(System.Globalization.SortVersion left, System.Globalization.SortVersion right) { throw new NotImplementedException(); }
+ public static bool operator !=(System.Globalization.SortVersion left, System.Globalization.SortVersion right) { throw new NotImplementedException(); }
+ }
+
+ public partial class StringInfo
+ {
+ public string SubstringByTextElements(int startingTextElement) { throw new NotImplementedException(); }
+ public string SubstringByTextElements(int startingTextElement, int lengthInTextElements) { throw new NotImplementedException(); }
+ }
+
+ public partial class TextInfo : System.ICloneable, System.Runtime.Serialization.IDeserializationCallback
+ {
+ public virtual int ANSICodePage { get { throw new NotImplementedException(); } }
+ public virtual int EBCDICCodePage { get { throw new NotImplementedException(); } }
+ [System.Runtime.InteropServices.ComVisibleAttribute(false)]
+ public int LCID { get { throw new NotImplementedException(); } }
+ public virtual int MacCodePage { get { throw new NotImplementedException(); } }
+ public virtual int OEMCodePage { get { throw new NotImplementedException(); } }
+ public string ToTitleCase(string str) { throw new NotImplementedException(); }
+ }
+} \ No newline at end of file
diff --git a/src/mscorlib/corefx/System/Globalization/StringInfo.cs b/src/mscorlib/corefx/System/Globalization/StringInfo.cs
new file mode 100644
index 0000000000..102f703beb
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/StringInfo.cs
@@ -0,0 +1,322 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+// Purpose: This class defines behaviors specific to a writing system.
+// A writing system is the collection of scripts and
+// orthographic rules required to represent a language as text.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class StringInfo
+ {
+ [OptionalField(VersionAdded = 2)]
+ private String _str;
+
+ [NonSerialized]
+ private int[] _indexes;
+
+ // Legacy constructor
+ public StringInfo() : this("") { }
+
+ // Primary, useful constructor
+ public StringInfo(String value)
+ {
+ this.String = value;
+ }
+
+ [OnDeserializing]
+ private void OnDeserializing(StreamingContext ctx)
+ {
+ _str = String.Empty;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ if (_str.Length == 0)
+ {
+ _indexes = null;
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override bool Equals(Object value)
+ {
+ StringInfo that = value as StringInfo;
+ if (that != null)
+ {
+ return (_str.Equals(that._str));
+ }
+ return (false);
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetHashCode()
+ {
+ return _str.GetHashCode();
+ }
+
+
+ // Our zero-based array of index values into the string. Initialize if
+ // our private array is not yet, in fact, initialized.
+ private int[] Indexes
+ {
+ get
+ {
+ if ((null == _indexes) && (0 < this.String.Length))
+ {
+ _indexes = StringInfo.ParseCombiningCharacters(this.String);
+ }
+
+ return (_indexes);
+ }
+ }
+
+ public String String
+ {
+ get
+ {
+ return (_str);
+ }
+ set
+ {
+ if (null == value)
+ {
+ throw new ArgumentNullException("String",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ _str = value;
+ _indexes = null;
+ }
+ }
+
+ public int LengthInTextElements
+ {
+ get
+ {
+ if (null == this.Indexes)
+ {
+ // Indexes not initialized, so assume length zero
+ return (0);
+ }
+
+ return (this.Indexes.Length);
+ }
+ }
+
+ public static String GetNextTextElement(String str)
+ {
+ return (GetNextTextElement(str, 0));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the code point count of the current text element.
+ //
+ // A combining class is defined as:
+ // A character/surrogate that has the following Unicode category:
+ // * NonSpacingMark (e.g. U+0300 COMBINING GRAVE ACCENT)
+ // * SpacingCombiningMark (e.g. U+ 0903 DEVANGARI SIGN VISARGA)
+ // * EnclosingMark (e.g. U+20DD COMBINING ENCLOSING CIRCLE)
+ //
+ // In the context of GetNextTextElement() and ParseCombiningCharacters(), a text element is defined as:
+ //
+ // 1. If a character/surrogate is in the following category, it is a text element.
+ // It can NOT further combine with characters in the combinging class to form a text element.
+ // * one of the Unicode category in the combinging class
+ // * UnicodeCategory.Format
+ // * UnicodeCateogry.Control
+ // * UnicodeCategory.OtherNotAssigned
+ // 2. Otherwise, the character/surrogate can be combined with characters in the combinging class to form a text element.
+ //
+ // Return:
+ // The length of the current text element
+ //
+ // Parameters:
+ // String str
+ // index The starting index
+ // len The total length of str (to define the upper boundary)
+ // ucCurrent The Unicode category pointed by Index. It will be updated to the uc of next character if this is not the last text element.
+ // currentCharCount The char count of an abstract char pointed by Index. It will be updated to the char count of next abstract character if this is not the last text element.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static int GetCurrentTextElementLen(String str, int index, int len, ref UnicodeCategory ucCurrent, ref int currentCharCount)
+ {
+ Contract.Assert(index >= 0 && len >= 0, "StringInfo.GetCurrentTextElementLen() : index = " + index + ", len = " + len);
+ Contract.Assert(index < len, "StringInfo.GetCurrentTextElementLen() : index = " + index + ", len = " + len);
+ if (index + currentCharCount == len)
+ {
+ // This is the last character/surrogate in the string.
+ return (currentCharCount);
+ }
+
+ // Call an internal GetUnicodeCategory, which will tell us both the unicode category, and also tell us if it is a surrogate pair or not.
+ int nextCharCount;
+ UnicodeCategory ucNext = CharUnicodeInfo.InternalGetUnicodeCategory(str, index + currentCharCount, out nextCharCount);
+ if (CharUnicodeInfo.IsCombiningCategory(ucNext))
+ {
+ // The next element is a combining class.
+ // Check if the current text element to see if it is a valid base category (i.e. it should not be a combining category,
+ // not a format character, and not a control character).
+
+ if (CharUnicodeInfo.IsCombiningCategory(ucCurrent)
+ || (ucCurrent == UnicodeCategory.Format)
+ || (ucCurrent == UnicodeCategory.Control)
+ || (ucCurrent == UnicodeCategory.OtherNotAssigned)
+ || (ucCurrent == UnicodeCategory.Surrogate)) // An unpair high surrogate or low surrogate
+ {
+ // Will fall thru and return the currentCharCount
+ }
+ else
+ {
+ int startIndex = index; // Remember the current index.
+
+ // We have a valid base characters, and we have a character (or surrogate) that is combining.
+ // Check if there are more combining characters to follow.
+ // Check if the next character is a nonspacing character.
+ index += currentCharCount + nextCharCount;
+
+ while (index < len)
+ {
+ ucNext = CharUnicodeInfo.InternalGetUnicodeCategory(str, index, out nextCharCount);
+ if (!CharUnicodeInfo.IsCombiningCategory(ucNext))
+ {
+ ucCurrent = ucNext;
+ currentCharCount = nextCharCount;
+ break;
+ }
+ index += nextCharCount;
+ }
+ return (index - startIndex);
+ }
+ }
+ // The return value will be the currentCharCount.
+ int ret = currentCharCount;
+ ucCurrent = ucNext;
+ // Update currentCharCount.
+ currentCharCount = nextCharCount;
+ return (ret);
+ }
+
+ // Returns the str containing the next text element in str starting at
+ // index index. If index is not supplied, then it will start at the beginning
+ // of str. It recognizes a base character plus one or more combining
+ // characters or a properly formed surrogate pair as a text element. See also
+ // the ParseCombiningCharacters() and the ParseSurrogates() methods.
+ public static String GetNextTextElement(String str, int index)
+ {
+ //
+ // Validate parameters.
+ //
+ if (str == null)
+ {
+ throw new ArgumentNullException("str");
+ }
+ Contract.EndContractBlock();
+
+ int len = str.Length;
+ if (index < 0 || index >= len)
+ {
+ if (index == len)
+ {
+ return (String.Empty);
+ }
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_Index);
+ }
+
+ int charLen;
+ UnicodeCategory uc = CharUnicodeInfo.InternalGetUnicodeCategory(str, index, out charLen);
+ return (str.Substring(index, GetCurrentTextElementLen(str, index, len, ref uc, ref charLen)));
+ }
+
+ public static TextElementEnumerator GetTextElementEnumerator(String str)
+ {
+ return (GetTextElementEnumerator(str, 0));
+ }
+
+ public static TextElementEnumerator GetTextElementEnumerator(String str, int index)
+ {
+ //
+ // Validate parameters.
+ //
+ if (str == null)
+ {
+ throw new ArgumentNullException("str");
+ }
+ Contract.EndContractBlock();
+
+ int len = str.Length;
+ if (index < 0 || (index > len))
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_Index);
+ }
+
+ return (new TextElementEnumerator(str, index, len));
+ }
+
+ /*
+ * Returns the indices of each base character or properly formed surrogate pair
+ * within the str. It recognizes a base character plus one or more combining
+ * characters or a properly formed surrogate pair as a text element and returns
+ * the index of the base character or high surrogate. Each index is the
+ * beginning of a text element within a str. The length of each element is
+ * easily computed as the difference between successive indices. The length of
+ * the array will always be less than or equal to the length of the str. For
+ * example, given the str \u4f00\u302a\ud800\udc00\u4f01, this method would
+ * return the indices: 0, 2, 4.
+ */
+
+ public static int[] ParseCombiningCharacters(String str)
+ {
+ if (str == null)
+ {
+ throw new ArgumentNullException("str");
+ }
+ Contract.EndContractBlock();
+
+ int len = str.Length;
+ int[] result = new int[len];
+ if (len == 0)
+ {
+ return (result);
+ }
+
+ int resultCount = 0;
+
+ int i = 0;
+ int currentCharLen;
+ UnicodeCategory currentCategory = CharUnicodeInfo.InternalGetUnicodeCategory(str, 0, out currentCharLen);
+
+ while (i < len)
+ {
+ result[resultCount++] = i;
+ i += GetCurrentTextElementLen(str, i, len, ref currentCategory, ref currentCharLen);
+ }
+
+ if (resultCount < len)
+ {
+ int[] returnArray = new int[resultCount];
+ Array.Copy(result, returnArray, resultCount);
+ return (returnArray);
+ }
+ return (result);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/TaiwanCalendar.cs b/src/mscorlib/corefx/System/Globalization/TaiwanCalendar.cs
new file mode 100644
index 0000000000..89b2e4a41d
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TaiwanCalendar.cs
@@ -0,0 +1,282 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ /*=================================TaiwanCalendar==========================
+ **
+ ** Taiwan calendar is based on the Gregorian calendar. And the year is an offset to Gregorian calendar.
+ ** That is,
+ ** Taiwan year = Gregorian year - 1911. So 1912/01/01 A.D. is Taiwan 1/01/01
+ **
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1912/01/01 9999/12/31
+ ** Taiwan 01/01/01 8088/12/31
+ ============================================================================*/
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public class TaiwanCalendar : Calendar
+ {
+ //
+ // The era value for the current era.
+ //
+
+ // Since
+ // Gregorian Year = Era Year + yearOffset
+ // When Gregorian Year 1912 is year 1, so that
+ // 1912 = 1 + yearOffset
+ // So yearOffset = 1911
+ //m_EraInfo[0] = new EraInfo(1, new DateTime(1912, 1, 1).Ticks, 1911, 1, GregorianCalendar.MaxYear - 1911);
+
+ // Initialize our era info.
+ internal static EraInfo[] taiwanEraInfo = new EraInfo[] {
+ new EraInfo( 1, 1912, 1, 1, 1911, 1, GregorianCalendar.MaxYear - 1911) // era #, start year/month/day, yearOffset, minEraYear
+ };
+
+ internal static volatile Calendar s_defaultInstance;
+
+ internal GregorianCalendarHelper helper;
+
+ /*=================================GetDefaultInstance==========================
+ **Action: Internal method to provide a default intance of TaiwanCalendar. Used by NLS+ implementation
+ ** and other calendars.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+ internal static Calendar GetDefaultInstance()
+ {
+ if (s_defaultInstance == null)
+ {
+ s_defaultInstance = new TaiwanCalendar();
+ }
+ return (s_defaultInstance);
+ }
+
+ internal static readonly DateTime calendarMinValue = new DateTime(1912, 1, 1);
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (calendarMinValue);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+ // Return the type of the Taiwan calendar.
+ //
+
+ public TaiwanCalendar()
+ {
+ try
+ {
+ new CultureInfo("zh-TW");
+ }
+ catch (ArgumentException e)
+ {
+ throw new TypeInitializationException(this.GetType().ToString(), e);
+ }
+ helper = new GregorianCalendarHelper(this, taiwanEraInfo);
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return CalendarId.TAIWAN;
+ }
+ }
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ return (helper.AddMonths(time, months));
+ }
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (helper.AddYears(time, years));
+ }
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ return (helper.GetDaysInMonth(year, month, era));
+ }
+
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ return (helper.GetDaysInYear(year, era));
+ }
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (helper.GetDayOfMonth(time));
+ }
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return (helper.GetDayOfWeek(time));
+ }
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (helper.GetDayOfYear(time));
+ }
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ return (helper.GetMonthsInYear(year, era));
+ }
+
+
+ [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems.
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ return (helper.GetWeekOfYear(time, rule, firstDayOfWeek));
+ }
+
+
+ public override int GetEra(DateTime time)
+ {
+ return (helper.GetEra(time));
+ }
+
+ public override int GetMonth(DateTime time)
+ {
+ return (helper.GetMonth(time));
+ }
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (helper.GetYear(time));
+ }
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ return (helper.IsLeapDay(year, month, day, era));
+ }
+
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ return (helper.IsLeapYear(year, era));
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ return (helper.GetLeapMonth(year, era));
+ }
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ return (helper.IsLeapMonth(year, month, era));
+ }
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ return (helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era));
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (helper.Eras);
+ }
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 99;
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > helper.MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ helper.MaxYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+ // For Taiwan calendar, four digit year is not used.
+ // Therefore, for any two digit number, we just return the original number.
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year <= 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year > helper.MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 1,
+ helper.MaxYear));
+ }
+ return (year);
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/TaiwanLunisolarCalendar.cs b/src/mscorlib/corefx/System/Globalization/TaiwanLunisolarCalendar.cs
new file mode 100644
index 0000000000..42b7f2473b
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TaiwanLunisolarCalendar.cs
@@ -0,0 +1,330 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about TaiwanLunisolarCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1912/02/18 2051/02/10
+ ** TaiwanLunisolar 1912/01/01 2050/13/29
+ */
+
+ [Serializable]
+ public class TaiwanLunisolarCalendar : EastAsianLunisolarCalendar
+ {
+ // Since
+ // Gregorian Year = Era Year + yearOffset
+ // When Gregorian Year 1912 is year 1, so that
+ // 1912 = 1 + yearOffset
+ // So yearOffset = 1911
+ //m_EraInfo[0] = new EraInfo(1, new DateTime(1912, 1, 1).Ticks, 1911, 1, GregorianCalendar.MaxYear - 1911);
+
+ // Initialize our era info.
+ internal static EraInfo[] taiwanLunisolarEraInfo = new EraInfo[] {
+ new EraInfo( 1, 1912, 1, 1, 1911, 1, GregorianCalendar.MaxYear - 1911) // era #, start year/month/day, yearOffset, minEraYear
+ };
+
+ internal GregorianCalendarHelper helper;
+
+ internal const int MIN_LUNISOLAR_YEAR = 1912;
+ internal const int MAX_LUNISOLAR_YEAR = 2050;
+
+ internal const int MIN_GREGORIAN_YEAR = 1912;
+ internal const int MIN_GREGORIAN_MONTH = 2;
+ internal const int MIN_GREGORIAN_DAY = 18;
+
+ internal const int MAX_GREGORIAN_YEAR = 2051;
+ internal const int MAX_GREGORIAN_MONTH = 2;
+ internal const int MAX_GREGORIAN_DAY = 10;
+
+ internal static DateTime minDate = new DateTime(MIN_GREGORIAN_YEAR, MIN_GREGORIAN_MONTH, MIN_GREGORIAN_DAY);
+ internal static DateTime maxDate = new DateTime((new DateTime(MAX_GREGORIAN_YEAR, MAX_GREGORIAN_MONTH, MAX_GREGORIAN_DAY, 23, 59, 59, 999)).Ticks + 9999);
+
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+
+
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // 1911 from ChineseLunisolarCalendar
+ return 384;
+ }
+ }
+
+ private static readonly int[,] s_yinfo =
+ {
+ /*Y LM Lmon Lday DaysPerMonth D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 #Days
+ 1912 */
+ { 0 , 2 , 18 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1913 */{ 0 , 2 , 6 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1914 */{ 5 , 1 , 26 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1915 */{ 0 , 2 , 14 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1916 */{ 0 , 2 , 3 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 0 355
+1917 */{ 2 , 1 , 23 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1918 */{ 0 , 2 , 11 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1919 */{ 7 , 2 , 1 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1920 */{ 0 , 2 , 20 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1921 */{ 0 , 2 , 8 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1922 */{ 5 , 1 , 28 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1923 */{ 0 , 2 , 16 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1924 */{ 0 , 2 , 5 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1925 */{ 4 , 1 , 24 , 44456 },/* 30 29 30 29 30 30 29 30 30 29 30 29 30 385
+1926 */{ 0 , 2 , 13 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1927 */{ 0 , 2 , 2 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1928 */{ 2 , 1 , 23 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1929 */{ 0 , 2 , 10 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1930 */{ 6 , 1 , 30 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1931 */{ 0 , 2 , 17 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1932 */{ 0 , 2 , 6 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1933 */{ 5 , 1 , 26 , 27976 },/* 29 30 30 29 30 30 29 30 29 30 29 29 30 384
+1934 */{ 0 , 2 , 14 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1935 */{ 0 , 2 , 4 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1936 */{ 3 , 1 , 24 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1937 */{ 0 , 2 , 11 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1938 */{ 7 , 1 , 31 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1939 */{ 0 , 2 , 19 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1940 */{ 0 , 2 , 8 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1941 */{ 6 , 1 , 27 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1942 */{ 0 , 2 , 15 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1943 */{ 0 , 2 , 5 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1944 */{ 4 , 1 , 25 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+1945 */{ 0 , 2 , 13 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1946 */{ 0 , 2 , 2 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+1947 */{ 2 , 1 , 22 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+1948 */{ 0 , 2 , 10 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1949 */{ 7 , 1 , 29 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+1950 */{ 0 , 2 , 17 , 27808 },/* 29 30 30 29 30 30 29 29 30 29 30 29 0 354
+1951 */{ 0 , 2 , 6 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1952 */{ 5 , 1 , 27 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+1953 */{ 0 , 2 , 14 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1954 */{ 0 , 2 , 3 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+1955 */{ 3 , 1 , 24 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1956 */{ 0 , 2 , 12 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1957 */{ 8 , 1 , 31 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 29 383
+1958 */{ 0 , 2 , 18 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+1959 */{ 0 , 2 , 8 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1960 */{ 6 , 1 , 28 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1961 */{ 0 , 2 , 15 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1962 */{ 0 , 2 , 5 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1963 */{ 4 , 1 , 25 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1964 */{ 0 , 2 , 13 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1965 */{ 0 , 2 , 2 , 21088 },/* 29 30 29 30 29 29 30 29 29 30 30 29 0 353
+1966 */{ 3 , 1 , 21 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1967 */{ 0 , 2 , 9 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1968 */{ 7 , 1 , 30 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1969 */{ 0 , 2 , 17 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1970 */{ 0 , 2 , 6 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1971 */{ 5 , 1 , 27 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1972 */{ 0 , 2 , 15 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+1973 */{ 0 , 2 , 3 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1974 */{ 4 , 1 , 23 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1975 */{ 0 , 2 , 11 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1976 */{ 8 , 1 , 31 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1977 */{ 0 , 2 , 18 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1978 */{ 0 , 2 , 7 , 46752 },/* 30 29 30 30 29 30 30 29 30 29 30 29 0 355
+1979 */{ 6 , 1 , 28 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1980 */{ 0 , 2 , 16 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1981 */{ 0 , 2 , 5 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1982 */{ 4 , 1 , 25 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1983 */{ 0 , 2 , 13 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1984 */{ 10 , 2 , 2 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1985 */{ 0 , 2 , 20 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1986 */{ 0 , 2 , 9 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1987 */{ 6 , 1 , 29 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 29 384
+1988 */{ 0 , 2 , 17 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1989 */{ 0 , 2 , 6 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1990 */{ 5 , 1 , 27 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1991 */{ 0 , 2 , 15 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1992 */{ 0 , 2 , 4 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1993 */{ 3 , 1 , 23 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1994 */{ 0 , 2 , 10 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1995 */{ 8 , 1 , 31 , 27432 },/* 29 30 30 29 30 29 30 30 29 29 30 29 30 384
+1996 */{ 0 , 2 , 19 , 23232 },/* 29 30 29 30 30 29 30 29 30 30 29 29 0 354
+1997 */{ 0 , 2 , 7 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1998 */{ 5 , 1 , 28 , 37736 },/* 30 29 29 30 29 29 30 30 29 30 30 29 30 384
+1999 */{ 0 , 2 , 16 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2000 */{ 0 , 2 , 5 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2001 */{ 4 , 1 , 24 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+2002 */{ 0 , 2 , 12 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2003 */{ 0 , 2 , 1 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2004 */{ 2 , 1 , 22 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2005 */{ 0 , 2 , 9 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+2006 */{ 7 , 1 , 29 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+2007 */{ 0 , 2 , 18 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+2008 */{ 0 , 2 , 7 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+2009 */{ 5 , 1 , 26 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+2010 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2011 */{ 0 , 2 , 3 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2012 */{ 4 , 1 , 23 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+2013 */{ 0 , 2 , 10 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2014 */{ 9 , 1 , 31 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2015 */{ 0 , 2 , 19 , 19360 },/* 29 30 29 29 30 29 30 30 30 29 30 29 0 354
+2016 */{ 0 , 2 , 8 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2017 */{ 6 , 1 , 28 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+2018 */{ 0 , 2 , 16 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2019 */{ 0 , 2 , 5 , 43312 },/* 30 29 30 29 30 29 29 30 29 29 30 30 0 354
+2020 */{ 4 , 1 , 25 , 29864 },/* 29 30 30 30 29 30 29 29 30 29 30 29 30 384
+2021 */{ 0 , 2 , 12 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2022 */{ 0 , 2 , 1 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2023 */{ 2 , 1 , 22 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+2024 */{ 0 , 2 , 10 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2025 */{ 6 , 1 , 29 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+2026 */{ 0 , 2 , 17 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+2027 */{ 0 , 2 , 6 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+2028 */{ 5 , 1 , 26 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+2029 */{ 0 , 2 , 13 , 54576 },/* 30 30 29 30 29 30 29 30 29 29 30 30 0 355
+2030 */{ 0 , 2 , 3 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+2031 */{ 3 , 1 , 23 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+2032 */{ 0 , 2 , 11 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2033 */{ 11 , 1 , 31 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+2034 */{ 0 , 2 , 19 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+2035 */{ 0 , 2 , 8 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2036 */{ 6 , 1 , 28 , 53848 },/* 30 30 29 30 29 29 30 29 29 30 29 30 30 384
+2037 */{ 0 , 2 , 15 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+2038 */{ 0 , 2 , 4 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2039 */{ 5 , 1 , 24 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 29 384
+2040 */{ 0 , 2 , 12 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+2041 */{ 0 , 2 , 1 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+2042 */{ 2 , 1 , 22 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+2043 */{ 0 , 2 , 10 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+2044 */{ 7 , 1 , 30 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+2045 */{ 0 , 2 , 17 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+2046 */{ 0 , 2 , 6 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+2047 */{ 5 , 1 , 26 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+2048 */{ 0 , 2 , 14 , 27936 },/* 29 30 30 29 30 30 29 30 29 29 30 29 0 354
+2049 */{ 0 , 2 , 2 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+2050 */{ 3 , 1 , 23 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+ */};
+
+
+ internal override int MinCalendarYear
+ {
+ get
+ {
+ return (MIN_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override int MaxCalendarYear
+ {
+ get
+ {
+ return (MAX_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override DateTime MinDate
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ internal override DateTime MaxDate
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ internal override EraInfo[] CalEraInfo
+ {
+ get
+ {
+ return (taiwanLunisolarEraInfo);
+ }
+ }
+
+ internal override int GetYearInfo(int LunarYear, int Index)
+ {
+ if ((LunarYear < MIN_LUNISOLAR_YEAR) || (LunarYear > MAX_LUNISOLAR_YEAR))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MIN_LUNISOLAR_YEAR,
+ MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return s_yinfo[LunarYear - MIN_LUNISOLAR_YEAR, Index];
+ }
+
+ internal override int GetYear(int year, DateTime time)
+ {
+ return helper.GetYear(year, time);
+ }
+
+ internal override int GetGregorianYear(int year, int era)
+ {
+ return helper.GetGregorianYear(year, era);
+ }
+
+ public TaiwanLunisolarCalendar()
+ {
+ helper = new GregorianCalendarHelper(this, taiwanLunisolarEraInfo);
+ }
+
+ public override int GetEra(DateTime time)
+ {
+ return (helper.GetEra(time));
+ }
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ return (CalendarId.TAIWAN);
+ }
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.TAIWANLUNISOLAR);
+ }
+ }
+
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (helper.Eras);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/TextElementEnumerator.cs b/src/mscorlib/corefx/System/Globalization/TextElementEnumerator.cs
new file mode 100644
index 0000000000..487ef11130
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TextElementEnumerator.cs
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+// Purpose:
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System.Collections;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ //
+ // This is public because GetTextElement() is public.
+ //
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public class TextElementEnumerator : IEnumerator
+ {
+ private String _str;
+ private int _index;
+ private int _startIndex;
+
+ [NonSerialized]
+ private int _strLen; // This is the length of the total string, counting from the beginning of string.
+
+ [NonSerialized]
+ private int _currTextElementLen; // The current text element lenght after MoveNext() is called.
+
+ [OptionalField(VersionAdded = 2)]
+ private UnicodeCategory _uc;
+
+ [OptionalField(VersionAdded = 2)]
+ private int _charLen; // The next abstract char to look at after MoveNext() is called. It could be 1 or 2, depending on if it is a surrogate or not.
+
+ internal TextElementEnumerator(String str, int startIndex, int strLen)
+ {
+ Contract.Assert(str != null, "TextElementEnumerator(): str != null");
+ Contract.Assert(startIndex >= 0 && strLen >= 0, "TextElementEnumerator(): startIndex >= 0 && strLen >= 0");
+ Contract.Assert(strLen >= startIndex, "TextElementEnumerator(): strLen >= startIndex");
+ _str = str;
+ _startIndex = startIndex;
+ _strLen = strLen;
+ Reset();
+ }
+
+ // the following fields is defined to keep the compatibility with Everett.
+ // don't change/remove the names/types of these fields.
+ private int _endIndex;
+ private int _nextTextElementLen;
+
+ [OnDeserializing]
+ private void OnDeserializing(StreamingContext ctx)
+ {
+ _charLen = -1;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ _strLen = _endIndex + 1;
+ _currTextElementLen = _nextTextElementLen;
+
+ if (_charLen == -1)
+ {
+ _uc = CharUnicodeInfo.InternalGetUnicodeCategory(_str, _index, out _charLen);
+ }
+ }
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx)
+ {
+ _endIndex = _strLen - 1;
+ _nextTextElementLen = _currTextElementLen;
+ }
+
+ public bool MoveNext()
+ {
+ if (_index >= _strLen)
+ {
+ // Make the _index to be greater than _strLen so that we can throw exception if GetTextElement() is called.
+ _index = _strLen + 1;
+ return (false);
+ }
+ _currTextElementLen = StringInfo.GetCurrentTextElementLen(_str, _index, _strLen, ref _uc, ref _charLen);
+ _index += _currTextElementLen;
+ return (true);
+ }
+
+ //
+ // Get the current text element.
+ //
+
+ public Object Current
+ {
+ get
+ {
+ return (GetTextElement());
+ }
+ }
+
+ //
+ // Get the current text element.
+ //
+
+ public String GetTextElement()
+ {
+ if (_index == _startIndex)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
+ }
+ if (_index > _strLen)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
+ }
+
+ return (_str.Substring(_index - _currTextElementLen, _currTextElementLen));
+ }
+
+ //
+ // Get the starting _index of the current text element.
+ //
+
+ public int ElementIndex
+ {
+ get
+ {
+ if (_index == _startIndex)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
+ }
+ return (_index - _currTextElementLen);
+ }
+ }
+
+
+ public void Reset()
+ {
+ _index = _startIndex;
+ if (_index < _strLen)
+ {
+ // If we have more than 1 character, get the category of the current char.
+ _uc = CharUnicodeInfo.InternalGetUnicodeCategory(_str, _index, out _charLen);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs
new file mode 100644
index 0000000000..8490057306
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+using System.Security;
+using System.Text;
+
+namespace System.Globalization
+{
+ public partial class TextInfo
+ {
+ [NonSerialized]
+ private Tristate _needsTurkishCasing = Tristate.NotInitialized;
+
+ //////////////////////////////////////////////////////////////////////////
+ ////
+ //// TextInfo Constructors
+ ////
+ //// Implements CultureInfo.TextInfo.
+ ////
+ //////////////////////////////////////////////////////////////////////////
+ internal unsafe TextInfo(CultureData cultureData)
+ {
+ _cultureData = cultureData;
+ _cultureName = _cultureData.CultureName;
+ _textInfoName = _cultureData.STEXTINFO;
+ FinishInitialization(_textInfoName);
+ }
+
+ private void FinishInitialization(string textInfoName)
+ {
+ }
+
+ [SecuritySafeCritical]
+ private unsafe string ChangeCase(string s, bool toUpper)
+ {
+ Contract.Assert(s != null);
+
+ if (s.Length == 0)
+ {
+ return string.Empty;
+ }
+
+ string result = string.FastAllocateString(s.Length);
+
+ fixed (char* pSource = s)
+ {
+ fixed (char* pResult = result)
+ {
+ if (IsAsciiCasingSameAsInvariant && s.IsAscii())
+ {
+ int length = s.Length;
+ char* a = pSource, b = pResult;
+ if (toUpper)
+ {
+ while (length-- != 0)
+ {
+ *b++ = ToUpperAsciiInvariant(*a++);
+ }
+ }
+ else
+ {
+ while (length-- != 0)
+ {
+ *b++ = ToLowerAsciiInvariant(*a++);
+ }
+ }
+ }
+ else
+ {
+ ChangeCase(pSource, s.Length, pResult, result.Length, toUpper);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ private unsafe char ChangeCase(char c, bool toUpper)
+ {
+ char dst = default(char);
+
+ ChangeCase(&c, 1, &dst, 1, toUpper);
+
+ return dst;
+ }
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+
+ private bool NeedsTurkishCasing(string localeName)
+ {
+ Contract.Assert(localeName != null);
+
+ return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("\u0131", "I", CompareOptions.IgnoreCase) == 0;
+ }
+
+ private bool IsInvariant { get { return _cultureName.Length == 0; } }
+
+ internal unsafe void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper)
+ {
+ if (IsInvariant)
+ {
+ Interop.GlobalizationInterop.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ }
+ else
+ {
+ if (_needsTurkishCasing == Tristate.NotInitialized)
+ {
+ _needsTurkishCasing = NeedsTurkishCasing(_textInfoName) ? Tristate.True : Tristate.False;
+ }
+ if (_needsTurkishCasing == Tristate.True)
+ {
+ Interop.GlobalizationInterop.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ }
+ else
+ {
+ Interop.GlobalizationInterop.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.Windows.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.Windows.cs
new file mode 100644
index 0000000000..238c51217b
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TextInfo.Windows.cs
@@ -0,0 +1,121 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ public partial class TextInfo
+ {
+ //////////////////////////////////////////////////////////////////////////
+ ////
+ //// TextInfo Constructors
+ ////
+ //// Implements CultureInfo.TextInfo.
+ ////
+ //////////////////////////////////////////////////////////////////////////
+ internal unsafe TextInfo(CultureData cultureData)
+ {
+ // This is our primary data source, we don't need most of the rest of this
+ _cultureData = cultureData;
+ _cultureName = _cultureData.CultureName;
+ _textInfoName = _cultureData.STEXTINFO;
+ FinishInitialization(_textInfoName);
+ }
+
+ private void FinishInitialization(string textInfoName)
+ {
+ const uint LCMAP_SORTHANDLE = 0x20000000;
+
+ long handle;
+ int ret = Interop.mincore.LCMapStringEx(_textInfoName, LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero);
+ _sortHandle = ret > 0 ? (IntPtr)handle : IntPtr.Zero;
+ }
+
+ private unsafe string ChangeCase(string s, bool toUpper)
+ {
+ Contract.Assert(s != null);
+
+ //
+ // Get the length of the string.
+ //
+ int nLengthInput = s.Length;
+
+ //
+ // Check if we have the empty string.
+ //
+ if (nLengthInput == 0)
+ {
+ return s;
+ }
+ else
+ {
+ int ret;
+
+ // Check for Invariant to avoid A/V in LCMapStringEx
+ uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING;
+
+ //
+ // Create the result string.
+ //
+ string result = string.FastAllocateString(nLengthInput);
+
+ fixed (char* pSource = s)
+ fixed (char* pResult = result)
+ {
+ ret = Interop.mincore.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName,
+ toUpper ? LCMAP_UPPERCASE | linguisticCasing : LCMAP_LOWERCASE | linguisticCasing,
+ pSource,
+ nLengthInput,
+ pResult,
+ nLengthInput,
+ null,
+ null,
+ _sortHandle);
+ }
+
+ if (0 == ret)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+
+ Contract.Assert(ret == nLengthInput, "Expected getting the same length of the original string");
+ return result;
+ }
+ }
+
+ private unsafe char ChangeCase(char c, bool toUpper)
+ {
+ char retVal = '\0';
+
+ // Check for Invariant to avoid A/V in LCMapStringEx
+ uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING;
+
+ Interop.mincore.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName,
+ toUpper ? LCMAP_UPPERCASE | linguisticCasing : LCMAP_LOWERCASE | linguisticCasing,
+ &c,
+ 1,
+ &retVal,
+ 1,
+ null,
+ null,
+ _sortHandle);
+
+ return retVal;
+ }
+
+ // PAL Ends here
+
+ private readonly IntPtr _sortHandle;
+
+ private const uint LCMAP_LINGUISTIC_CASING = 0x01000000;
+ private const uint LCMAP_LOWERCASE = 0x00000100;
+ private const uint LCMAP_UPPERCASE = 0x00000200;
+
+ private static bool IsInvariantLocale(string localeName)
+ {
+ return localeName == "";
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.cs
new file mode 100644
index 0000000000..6dadb5856a
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TextInfo.cs
@@ -0,0 +1,457 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+// Purpose: This Class defines behaviors specific to a writing system.
+// A writing system is the collection of scripts and
+// orthographic rules required to represent a language as text.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Text;
+using System.Threading;
+
+namespace System.Globalization
+{
+ [Serializable]
+ public partial class TextInfo : ICloneable, IDeserializationCallback
+ {
+ ////--------------------------------------------------------------------//
+ //// Internal Information //
+ ////--------------------------------------------------------------------//
+
+ private enum Tristate : byte
+ {
+ NotInitialized,
+ True,
+ False,
+ }
+
+ ////
+ //// Variables.
+ ////
+
+ [OptionalField(VersionAdded = 2)]
+ private String _listSeparator;
+ [OptionalField(VersionAdded = 2)]
+ private bool _isReadOnly = false;
+
+ //// _cultureName is the name of the creating culture. Note that we consider this authoratative,
+ //// if the culture's textinfo changes when deserializing, then behavior may change.
+ //// (ala Whidbey behavior). This is the only string Arrowhead needs to serialize.
+ //// _cultureData is the data that backs this class.
+ //// _textInfoName is the actual name of the textInfo (from cultureData.STEXTINFO)
+ //// this can be the same as _cultureName on Silverlight since the OS knows
+ //// how to do the sorting. However in the desktop, when we call the sorting dll, it doesn't
+ //// know how to resolve custom locle names to sort ids so we have to have alredy resolved this.
+ ////
+
+ [OptionalField(VersionAdded = 3)]
+ private String _cultureName; // Name of the culture that created this text info
+ [NonSerialized]
+ private CultureData _cultureData; // Data record for the culture that made us, not for this textinfo
+ [NonSerialized]
+ private String _textInfoName; // Name of the text info we're using (ie: _cultureData.STEXTINFO)
+ [NonSerialized]
+ private Tristate _isAsciiCasingSameAsInvariant = Tristate.NotInitialized;
+
+ // Invariant text info
+ internal static TextInfo Invariant
+ {
+ get
+ {
+ if (s_Invariant == null)
+ s_Invariant = new TextInfo(CultureData.Invariant);
+ return s_Invariant;
+ }
+ }
+ internal volatile static TextInfo s_Invariant;
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx) { }
+
+ [OnDeserializing]
+ private void OnDeserializing(StreamingContext ctx)
+ {
+ // Clear these so we can check if we've fixed them yet
+ _cultureData = null;
+ _cultureName = null;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ OnDeserialized();
+ }
+
+ void IDeserializationCallback.OnDeserialization(Object sender)
+ {
+ OnDeserialized();
+ }
+
+ private void OnDeserialized()
+ {
+ // this method will be called twice because of the support of IDeserializationCallback
+ if (_cultureData == null)
+ {
+ // Get the text info name belonging to that culture
+ _cultureData = CultureInfo.GetCultureInfo(_cultureName).m_cultureData;
+ _textInfoName = _cultureData.STEXTINFO;
+ FinishInitialization(_textInfoName);
+ }
+ }
+
+ //
+ // Internal ordinal comparison functions
+ //
+
+ internal static int GetHashCodeOrdinalIgnoreCase(String s)
+ {
+ // This is the same as an case insensitive hash for Invariant
+ // (not necessarily true for sorting, but OK for casing & then we apply normal hash code rules)
+ return (Invariant.GetCaseInsensitiveHashCode(s));
+ }
+
+ // Currently we don't have native functions to do this, so we do it the hard way
+ internal static int IndexOfStringOrdinalIgnoreCase(String source, String value, int startIndex, int count)
+ {
+ if (count > source.Length || count < 0 || startIndex < 0 || startIndex >= source.Length || startIndex + count > source.Length)
+ {
+ return -1;
+ }
+
+ return CompareInfo.IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ }
+
+ // Currently we don't have native functions to do this, so we do it the hard way
+ internal static int LastIndexOfStringOrdinalIgnoreCase(String source, String value, int startIndex, int count)
+ {
+ if (count > source.Length || count < 0 || startIndex < 0 || startIndex > source.Length - 1 || (startIndex - count + 1 < 0))
+ {
+ return -1;
+ }
+
+ return CompareInfo.LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ ////
+ //// CultureName
+ ////
+ //// The name of the culture associated with the current TextInfo.
+ ////
+ //////////////////////////////////////////////////////////////////////////
+ public string CultureName
+ {
+ get
+ {
+ return _textInfoName;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsReadOnly
+ //
+ // Detect if the object is readonly.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public bool IsReadOnly
+ {
+ get { return (_isReadOnly); }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ ////
+ //// Clone
+ ////
+ //// Is the implementation of IColnable.
+ ////
+ //////////////////////////////////////////////////////////////////////////
+ public virtual Object Clone()
+ {
+ object o = MemberwiseClone();
+ ((TextInfo)o).SetReadOnlyState(false);
+ return (o);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ReadOnly
+ //
+ // Create a cloned readonly instance or return the input one if it is
+ // readonly.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ internal static TextInfo ReadOnly(TextInfo textInfo)
+ {
+ if (textInfo == null) { throw new ArgumentNullException("textInfo"); }
+ Contract.EndContractBlock();
+ if (textInfo.IsReadOnly) { return (textInfo); }
+
+ TextInfo clonedTextInfo = (TextInfo)(textInfo.MemberwiseClone());
+ clonedTextInfo.SetReadOnlyState(true);
+
+ return (clonedTextInfo);
+ }
+
+ private void VerifyWritable()
+ {
+ if (_isReadOnly)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+ }
+
+ internal void SetReadOnlyState(bool readOnly)
+ {
+ _isReadOnly = readOnly;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ListSeparator
+ //
+ // Returns the string used to separate items in a list.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String ListSeparator
+ {
+ get
+ {
+ if (_listSeparator == null)
+ {
+ _listSeparator = _cultureData.SLIST;
+ }
+ return (_listSeparator);
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_String);
+ }
+ VerifyWritable();
+ _listSeparator = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToLower
+ //
+ // Converts the character or string to lower case. Certain locales
+ // have different casing semantics from the file systems in Win32.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public unsafe virtual char ToLower(char c)
+ {
+ if (IsAscii(c) && IsAsciiCasingSameAsInvariant)
+ {
+ return ToLowerAsciiInvariant(c);
+ }
+ return (ChangeCase(c, toUpper: false));
+ }
+
+ public unsafe virtual String ToLower(String str)
+ {
+ if (str == null) { throw new ArgumentNullException("str"); }
+
+ return ChangeCase(str, toUpper: false);
+ }
+
+ private static Char ToLowerAsciiInvariant(Char c)
+ {
+ if ((uint)(c - 'A') <= (uint)('Z' - 'A'))
+ {
+ c = (Char)(c | 0x20);
+ }
+ return c;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToUpper
+ //
+ // Converts the character or string to upper case. Certain locales
+ // have different casing semantics from the file systems in Win32.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public unsafe virtual char ToUpper(char c)
+ {
+ if (IsAscii(c) && IsAsciiCasingSameAsInvariant)
+ {
+ return ToUpperAsciiInvariant(c);
+ }
+ return (ChangeCase(c, toUpper: true));
+ }
+
+ public unsafe virtual String ToUpper(String str)
+ {
+ if (str == null) { throw new ArgumentNullException("str"); }
+
+ return ChangeCase(str, toUpper: true);
+ }
+
+ private static Char ToUpperAsciiInvariant(Char c)
+ {
+ if ((uint)(c - 'a') <= (uint)('z' - 'a'))
+ {
+ c = (Char)(c & ~0x20);
+ }
+ return c;
+ }
+
+ static private bool IsAscii(Char c)
+ {
+ return c < 0x80;
+ }
+
+ private bool IsAsciiCasingSameAsInvariant
+ {
+ get
+ {
+ if (_isAsciiCasingSameAsInvariant == Tristate.NotInitialized)
+ {
+ _isAsciiCasingSameAsInvariant = CultureInfo.GetCultureInfo(_textInfoName).CompareInfo.Compare("abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ CompareOptions.IgnoreCase) == 0 ? Tristate.True : Tristate.False;
+ }
+ return _isAsciiCasingSameAsInvariant == Tristate.True;
+ }
+ }
+
+ // IsRightToLeft
+ //
+ // Returns true if the dominant direction of text and UI such as the relative position of buttons and scroll bars
+ //
+ public bool IsRightToLeft
+ {
+ get
+ {
+ return _cultureData.IsRightToLeft;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Equals
+ //
+ // Implements Object.Equals(). Returns a boolean indicating whether
+ // or not object refers to the same CultureInfo as the current instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override bool Equals(Object obj)
+ {
+ TextInfo that = obj as TextInfo;
+
+ if (that != null)
+ {
+ return this.CultureName.Equals(that.CultureName);
+ }
+
+ return (false);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCode
+ //
+ // Implements Object.GetHashCode(). Returns the hash code for the
+ // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
+ // and B where A.Equals(B) is true.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override int GetHashCode()
+ {
+ return (this.CultureName.GetHashCode());
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Implements Object.ToString(). Returns a string describing the
+ // TextInfo.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override String ToString()
+ {
+ return ("TextInfo - " + _cultureData.CultureName);
+ }
+
+ //
+ // Get case-insensitive hash code for the specified string.
+ //
+ internal unsafe int GetCaseInsensitiveHashCode(String str)
+ {
+ // Validate inputs
+ if (str == null)
+ {
+ throw new ArgumentNullException("str");
+ }
+
+ // This code assumes that ASCII casing is safe for whatever context is passed in.
+ // this is true today, because we only ever call these methods on Invariant. It would be ideal to refactor
+ // these methods so they were correct by construction and we could only ever use Invariant.
+
+ uint hash = 5381;
+ uint c;
+
+ // Note: We assume that str contains only ASCII characters until
+ // we hit a non-ASCII character to optimize the common case.
+ for (int i = 0; i < str.Length; i++)
+ {
+ c = str[i];
+ if (c >= 0x80)
+ {
+ return GetCaseInsensitiveHashCodeSlow(str);
+ }
+
+ // If we have a lowercase character, ANDing off 0x20
+ // will make it an uppercase character.
+ if ((c - 'a') <= ('z' - 'a'))
+ {
+ c = (uint)((int)c & ~0x20);
+ }
+
+ hash = ((hash << 5) + hash) ^ c;
+ }
+
+ return (int)hash;
+ }
+
+ private unsafe int GetCaseInsensitiveHashCodeSlow(String str)
+ {
+ Contract.Assert(str != null);
+
+ string upper = ToUpper(str);
+
+ uint hash = 5381;
+ uint c;
+
+ for (int i = 0; i < upper.Length; i++)
+ {
+ c = upper[i];
+ hash = ((hash << 5) + hash) ^ c;
+ }
+
+ return (int)hash;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/ThaiBuddhistCalendar.cs b/src/mscorlib/corefx/System/Globalization/ThaiBuddhistCalendar.cs
new file mode 100644
index 0000000000..b42af30c04
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/ThaiBuddhistCalendar.cs
@@ -0,0 +1,233 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ /*=================================ThaiBuddhistCalendar==========================
+ **
+ ** ThaiBuddhistCalendar is based on Gregorian calendar. Its year value has
+ ** an offset to the Gregorain calendar.
+ **
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 0001/01/01 9999/12/31
+ ** Thai 0544/01/01 10542/12/31
+ ============================================================================*/
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public class ThaiBuddhistCalendar : Calendar
+ {
+ // Initialize our era info.
+ internal static EraInfo[] thaiBuddhistEraInfo = new EraInfo[] {
+ new EraInfo( 1, 1, 1, 1, -543, 544, GregorianCalendar.MaxYear + 543) // era #, start year/month/day, yearOffset, minEraYear
+ };
+
+ //
+ // The era value for the current era.
+ //
+
+ public const int ThaiBuddhistEra = 1;
+
+ internal GregorianCalendarHelper helper;
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MinValue);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+ public ThaiBuddhistCalendar()
+ {
+ helper = new GregorianCalendarHelper(this, thaiBuddhistEraInfo);
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.THAI);
+ }
+ }
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ return (helper.AddMonths(time, months));
+ }
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (helper.AddYears(time, years));
+ }
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ return (helper.GetDaysInMonth(year, month, era));
+ }
+
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ return (helper.GetDaysInYear(year, era));
+ }
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (helper.GetDayOfMonth(time));
+ }
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return (helper.GetDayOfWeek(time));
+ }
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (helper.GetDayOfYear(time));
+ }
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ return (helper.GetMonthsInYear(year, era));
+ }
+
+
+ [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems.
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ return (helper.GetWeekOfYear(time, rule, firstDayOfWeek));
+ }
+
+
+ public override int GetEra(DateTime time)
+ {
+ return (helper.GetEra(time));
+ }
+
+ public override int GetMonth(DateTime time)
+ {
+ return (helper.GetMonth(time));
+ }
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (helper.GetYear(time));
+ }
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ return (helper.IsLeapDay(year, month, day, era));
+ }
+
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ return (helper.IsLeapYear(year, era));
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetLeapMonth(int year, int era)
+ {
+ return (helper.GetLeapMonth(year, era));
+ }
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ return (helper.IsLeapMonth(year, month, era));
+ }
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ return (helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era));
+ }
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (helper.Eras);
+ }
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 2572;
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ if (value < 99 || value > helper.MaxYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ 99,
+ helper.MaxYear));
+ }
+ twoDigitYearMax = value;
+ }
+ }
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ return (helper.ToFourDigitYear(year, this.TwoDigitYearMax));
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/TimeSpanStyles.cs b/src/mscorlib/corefx/System/Globalization/TimeSpanStyles.cs
new file mode 100644
index 0000000000..68a47bcbe6
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/TimeSpanStyles.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Globalization
+{
+ [Flags]
+ public enum TimeSpanStyles
+ {
+ None = 0x00000000,
+ AssumeNegative = 0x00000001,
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/UmAlQuraCalendar.cs b/src/mscorlib/corefx/System/Globalization/UmAlQuraCalendar.cs
new file mode 100644
index 0000000000..1116722fe9
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/UmAlQuraCalendar.cs
@@ -0,0 +1,862 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about UmAlQuraCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1900/04/30 2077/05/13
+ ** UmAlQura 1318/01/01 1500/12/30
+ */
+
+ [Serializable]
+ public partial class UmAlQuraCalendar : Calendar
+ {
+ internal const int MinCalendarYear = 1318;
+ internal const int MaxCalendarYear = 1500;
+
+ internal struct DateMapping
+ {
+ internal DateMapping(int MonthsLengthFlags, int GYear, int GMonth, int GDay)
+ {
+ HijriMonthsLengthFlags = MonthsLengthFlags;
+ GregorianDate = new DateTime(GYear, GMonth, GDay);
+ }
+ internal int HijriMonthsLengthFlags;
+ internal DateTime GregorianDate;
+ }
+
+ private static readonly DateMapping[] s_hijriYearInfo = InitDateMapping();
+
+ private static DateMapping[] InitDateMapping()
+ {
+ short[] rawData = new short[]
+ {
+ //These data is taken from Tables/Excel/UmAlQura.xls please make sure that the two places are in sync
+ /* DaysPerM GY GM GD D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12
+ 1318*/0x02EA, 1900, 4, 30,/* 0 1 0 1 0 1 1 1 0 1 0 0 4/30/1900
+ 1319*/0x06E9, 1901, 4, 19,/* 1 0 0 1 0 1 1 1 0 1 1 0 4/19/1901
+ 1320*/0x0ED2, 1902, 4, 9,/* 0 1 0 0 1 0 1 1 0 1 1 1 4/9/1902
+ 1321*/0x0EA4, 1903, 3, 30,/* 0 0 1 0 0 1 0 1 0 1 1 1 3/30/1903
+ 1322*/0x0D4A, 1904, 3, 18,/* 0 1 0 1 0 0 1 0 1 0 1 1 3/18/1904
+ 1323*/0x0A96, 1905, 3, 7,/* 0 1 1 0 1 0 0 1 0 1 0 1 3/7/1905
+ 1324*/0x0536, 1906, 2, 24,/* 0 1 1 0 1 1 0 0 1 0 1 0 2/24/1906
+ 1325*/0x0AB5, 1907, 2, 13,/* 1 0 1 0 1 1 0 1 0 1 0 1 2/13/1907
+ 1326*/0x0DAA, 1908, 2, 3,/* 0 1 0 1 0 1 0 1 1 0 1 1 2/3/1908
+ 1327*/0x0BA4, 1909, 1, 23,/* 0 0 1 0 0 1 0 1 1 1 0 1 1/23/1909
+ 1328*/0x0B49, 1910, 1, 12,/* 1 0 0 1 0 0 1 0 1 1 0 1 1/12/1910
+ 1329*/0x0A93, 1911, 1, 1,/* 1 1 0 0 1 0 0 1 0 1 0 1 1/1/1911
+ 1330*/0x052B, 1911, 12, 21,/* 1 1 0 1 0 1 0 0 1 0 1 0 12/21/1911
+ 1331*/0x0A57, 1912, 12, 9,/* 1 1 1 0 1 0 1 0 0 1 0 1 12/9/1912
+ 1332*/0x04B6, 1913, 11, 29,/* 0 1 1 0 1 1 0 1 0 0 1 0 11/29/1913
+ 1333*/0x0AB5, 1914, 11, 18,/* 1 0 1 0 1 1 0 1 0 1 0 1 11/18/1914
+ 1334*/0x05AA, 1915, 11, 8,/* 0 1 0 1 0 1 0 1 1 0 1 0 11/8/1915
+ 1335*/0x0D55, 1916, 10, 27,/* 1 0 1 0 1 0 1 0 1 0 1 1 10/27/1916
+ 1336*/0x0D2A, 1917, 10, 17,/* 0 1 0 1 0 1 0 0 1 0 1 1 10/17/1917
+ 1337*/0x0A56, 1918, 10, 6,/* 0 1 1 0 1 0 1 0 0 1 0 1 10/6/1918
+ 1338*/0x04AE, 1919, 9, 25,/* 0 1 1 1 0 1 0 1 0 0 1 0 9/25/1919
+ 1339*/0x095D, 1920, 9, 13,/* 1 0 1 1 1 0 1 0 1 0 0 1 9/13/1920
+ 1340*/0x02EC, 1921, 9, 3,/* 0 0 1 1 0 1 1 1 0 1 0 0 9/3/1921
+ 1341*/0x06D5, 1922, 8, 23,/* 1 0 1 0 1 0 1 1 0 1 1 0 8/23/1922
+ 1342*/0x06AA, 1923, 8, 13,/* 0 1 0 1 0 1 0 1 0 1 1 0 8/13/1923
+ 1343*/0x0555, 1924, 8, 1,/* 1 0 1 0 1 0 1 0 1 0 1 0 8/1/1924
+ 1344*/0x04AB, 1925, 7, 21,/* 1 1 0 1 0 1 0 1 0 0 1 0 7/21/1925
+ 1345*/0x095B, 1926, 7, 10,/* 1 1 0 1 1 0 1 0 1 0 0 1 7/10/1926
+ 1346*/0x02BA, 1927, 6, 30,/* 0 1 0 1 1 1 0 1 0 1 0 0 6/30/1927
+ 1347*/0x0575, 1928, 6, 18,/* 1 0 1 0 1 1 1 0 1 0 1 0 6/18/1928
+ 1348*/0x0BB2, 1929, 6, 8,/* 0 1 0 0 1 1 0 1 1 1 0 1 6/8/1929
+ 1349*/0x0764, 1930, 5, 29,/* 0 0 1 0 0 1 1 0 1 1 1 0 5/29/1930
+ 1350*/0x0749, 1931, 5, 18,/* 1 0 0 1 0 0 1 0 1 1 1 0 5/18/1931
+ 1351*/0x0655, 1932, 5, 6,/* 1 0 1 0 1 0 1 0 0 1 1 0 5/6/1932
+ 1352*/0x02AB, 1933, 4, 25,/* 1 1 0 1 0 1 0 1 0 1 0 0 4/25/1933
+ 1353*/0x055B, 1934, 4, 14,/* 1 1 0 1 1 0 1 0 1 0 1 0 4/14/1934
+ 1354*/0x0ADA, 1935, 4, 4,/* 0 1 0 1 1 0 1 1 0 1 0 1 4/4/1935
+ 1355*/0x06D4, 1936, 3, 24,/* 0 0 1 0 1 0 1 1 0 1 1 0 3/24/1936
+ 1356*/0x0EC9, 1937, 3, 13,/* 1 0 0 1 0 0 1 1 0 1 1 1 3/13/1937
+ 1357*/0x0D92, 1938, 3, 3,/* 0 1 0 0 1 0 0 1 1 0 1 1 3/3/1938
+ 1358*/0x0D25, 1939, 2, 20,/* 1 0 1 0 0 1 0 0 1 0 1 1 2/20/1939
+ 1359*/0x0A4D, 1940, 2, 9,/* 1 0 1 1 0 0 1 0 0 1 0 1 2/9/1940
+ 1360*/0x02AD, 1941, 1, 28,/* 1 0 1 1 0 1 0 1 0 1 0 0 1/28/1941
+ 1361*/0x056D, 1942, 1, 17,/* 1 0 1 1 0 1 1 0 1 0 1 0 1/17/1942
+ 1362*/0x0B6A, 1943, 1, 7,/* 0 1 0 1 0 1 1 0 1 1 0 1 1/7/1943
+ 1363*/0x0B52, 1943, 12, 28,/* 0 1 0 0 1 0 1 0 1 1 0 1 12/28/1943
+ 1364*/0x0AA5, 1944, 12, 16,/* 1 0 1 0 0 1 0 1 0 1 0 1 12/16/1944
+ 1365*/0x0A4B, 1945, 12, 5,/* 1 1 0 1 0 0 1 0 0 1 0 1 12/5/1945
+ 1366*/0x0497, 1946, 11, 24,/* 1 1 1 0 1 0 0 1 0 0 1 0 11/24/1946
+ 1367*/0x0937, 1947, 11, 13,/* 1 1 1 0 1 1 0 0 1 0 0 1 11/13/1947
+ 1368*/0x02B6, 1948, 11, 2,/* 0 1 1 0 1 1 0 1 0 1 0 0 11/2/1948
+ 1369*/0x0575, 1949, 10, 22,/* 1 0 1 0 1 1 1 0 1 0 1 0 10/22/1949
+ 1370*/0x0D6A, 1950, 10, 12,/* 0 1 0 1 0 1 1 0 1 0 1 1 10/12/1950
+ 1371*/0x0D52, 1951, 10, 2,/* 0 1 0 0 1 0 1 0 1 0 1 1 10/2/1951
+ 1372*/0x0A96, 1952, 9, 20,/* 0 1 1 0 1 0 0 1 0 1 0 1 9/20/1952
+ 1373*/0x092D, 1953, 9, 9,/* 1 0 1 1 0 1 0 0 1 0 0 1 9/9/1953
+ 1374*/0x025D, 1954, 8, 29,/* 1 0 1 1 1 0 1 0 0 1 0 0 8/29/1954
+ 1375*/0x04DD, 1955, 8, 18,/* 1 0 1 1 1 0 1 1 0 0 1 0 8/18/1955
+ 1376*/0x0ADA, 1956, 8, 7,/* 0 1 0 1 1 0 1 1 0 1 0 1 8/7/1956
+ 1377*/0x05D4, 1957, 7, 28,/* 0 0 1 0 1 0 1 1 1 0 1 0 7/28/1957
+ 1378*/0x0DA9, 1958, 7, 17,/* 1 0 0 1 0 1 0 1 1 0 1 1 7/17/1958
+ 1379*/0x0D52, 1959, 7, 7,/* 0 1 0 0 1 0 1 0 1 0 1 1 7/7/1959
+ 1380*/0x0AAA, 1960, 6, 25,/* 0 1 0 1 0 1 0 1 0 1 0 1 6/25/1960
+ 1381*/0x04D6, 1961, 6, 14,/* 0 1 1 0 1 0 1 1 0 0 1 0 6/14/1961
+ 1382*/0x09B6, 1962, 6, 3,/* 0 1 1 0 1 1 0 1 1 0 0 1 6/3/1962
+ 1383*/0x0374, 1963, 5, 24,/* 0 0 1 0 1 1 1 0 1 1 0 0 5/24/1963
+ 1384*/0x0769, 1964, 5, 12,/* 1 0 0 1 0 1 1 0 1 1 1 0 5/12/1964
+ 1385*/0x0752, 1965, 5, 2,/* 0 1 0 0 1 0 1 0 1 1 1 0 5/2/1965
+ 1386*/0x06A5, 1966, 4, 21,/* 1 0 1 0 0 1 0 1 0 1 1 0 4/21/1966
+ 1387*/0x054B, 1967, 4, 10,/* 1 1 0 1 0 0 1 0 1 0 1 0 4/10/1967
+ 1388*/0x0AAB, 1968, 3, 29,/* 1 1 0 1 0 1 0 1 0 1 0 1 3/29/1968
+ 1389*/0x055A, 1969, 3, 19,/* 0 1 0 1 1 0 1 0 1 0 1 0 3/19/1969
+ 1390*/0x0AD5, 1970, 3, 8,/* 1 0 1 0 1 0 1 1 0 1 0 1 3/8/1970
+ 1391*/0x0DD2, 1971, 2, 26,/* 0 1 0 0 1 0 1 1 1 0 1 1 2/26/1971
+ 1392*/0x0DA4, 1972, 2, 16,/* 0 0 1 0 0 1 0 1 1 0 1 1 2/16/1972
+ 1393*/0x0D49, 1973, 2, 4,/* 1 0 0 1 0 0 1 0 1 0 1 1 2/4/1973
+ 1394*/0x0A95, 1974, 1, 24,/* 1 0 1 0 1 0 0 1 0 1 0 1 1/24/1974
+ 1395*/0x052D, 1975, 1, 13,/* 1 0 1 1 0 1 0 0 1 0 1 0 1/13/1975
+ 1396*/0x0A5D, 1976, 1, 2,/* 1 0 1 1 1 0 1 0 0 1 0 1 1/2/1976
+ 1397*/0x055A, 1976, 12, 22,/* 0 1 0 1 1 0 1 0 1 0 1 0 12/22/1976
+ 1398*/0x0AD5, 1977, 12, 11,/* 1 0 1 0 1 0 1 1 0 1 0 1 12/11/1977
+ 1399*/0x06AA, 1978, 12, 1,/* 0 1 0 1 0 1 0 1 0 1 1 0 12/1/1978
+ 1400*/0x0695, 1979, 11, 20,/* 1 0 1 0 1 0 0 1 0 1 1 0 11/20/1979
+ 1401*/0x052B, 1980, 11, 8,/* 1 1 0 1 0 1 0 0 1 0 1 0 11/8/1980
+ 1402*/0x0A57, 1981, 10, 28,/* 1 1 1 0 1 0 1 0 0 1 0 1 10/28/1981
+ 1403*/0x04AE, 1982, 10, 18,/* 0 1 1 1 0 1 0 1 0 0 1 0 10/18/1982
+ 1404*/0x0976, 1983, 10, 7,/* 0 1 1 0 1 1 1 0 1 0 0 1 10/7/1983
+ 1405*/0x056C, 1984, 9, 26,/* 0 0 1 1 0 1 1 0 1 0 1 0 9/26/1984
+ 1406*/0x0B55, 1985, 9, 15,/* 1 0 1 0 1 0 1 0 1 1 0 1 9/15/1985
+ 1407*/0x0AAA, 1986, 9, 5,/* 0 1 0 1 0 1 0 1 0 1 0 1 9/5/1986
+ 1408*/0x0A55, 1987, 8, 25,/* 1 0 1 0 1 0 1 0 0 1 0 1 8/25/1987
+ 1409*/0x04AD, 1988, 8, 13,/* 1 0 1 1 0 1 0 1 0 0 1 0 8/13/1988
+ 1410*/0x095D, 1989, 8, 2,/* 1 0 1 1 1 0 1 0 1 0 0 1 8/2/1989
+ 1411*/0x02DA, 1990, 7, 23,/* 0 1 0 1 1 0 1 1 0 1 0 0 7/23/1990
+ 1412*/0x05D9, 1991, 7, 12,/* 1 0 0 1 1 0 1 1 1 0 1 0 7/12/1991
+ 1413*/0x0DB2, 1992, 7, 1,/* 0 1 0 0 1 1 0 1 1 0 1 1 7/1/1992
+ 1414*/0x0BA4, 1993, 6, 21,/* 0 0 1 0 0 1 0 1 1 1 0 1 6/21/1993
+ 1415*/0x0B4A, 1994, 6, 10,/* 0 1 0 1 0 0 1 0 1 1 0 1 6/10/1994
+ 1416*/0x0A55, 1995, 5, 30,/* 1 0 1 0 1 0 1 0 0 1 0 1 5/30/1995
+ 1417*/0x02B5, 1996, 5, 18,/* 1 0 1 0 1 1 0 1 0 1 0 0 5/18/1996
+ 1418*/0x0575, 1997, 5, 7,/* 1 0 1 0 1 1 1 0 1 0 1 0 5/7/1997
+ 1419*/0x0B6A, 1998, 4, 27,/* 0 1 0 1 0 1 1 0 1 1 0 1 4/27/1998
+ 1420*/0x0BD2, 1999, 4, 17,/* 0 1 0 0 1 0 1 1 1 1 0 1 4/17/1999
+ 1421*/0x0BC4, 2000, 4, 6,/* 0 0 1 0 0 0 1 1 1 1 0 1 4/6/2000
+ 1422*/0x0B89, 2001, 3, 26,/* 1 0 0 1 0 0 0 1 1 1 0 1 3/26/2001
+ 1423*/0x0A95, 2002, 3, 15,/* 1 0 1 0 1 0 0 1 0 1 0 1 3/15/2002
+ 1424*/0x052D, 2003, 3, 4,/* 1 0 1 1 0 1 0 0 1 0 1 0 3/4/2003
+ 1425*/0x05AD, 2004, 2, 21,/* 1 0 1 1 0 1 0 1 1 0 1 0 2/21/2004
+ 1426*/0x0B6A, 2005, 2, 10,/* 0 1 0 1 0 1 1 0 1 1 0 1 2/10/2005
+ 1427*/0x06D4, 2006, 1, 31,/* 0 0 1 0 1 0 1 1 0 1 1 0 1/31/2006
+ 1428*/0x0DC9, 2007, 1, 20,/* 1 0 0 1 0 0 1 1 1 0 1 1 1/20/2007
+ 1429*/0x0D92, 2008, 1, 10,/* 0 1 0 0 1 0 0 1 1 0 1 1 1/10/2008
+ 1430*/0x0AA6, 2008, 12, 29,/* 0 1 1 0 0 1 0 1 0 1 0 1 12/29/2008
+ 1431*/0x0956, 2009, 12, 18,/* 0 1 1 0 1 0 1 0 1 0 0 1 12/18/2009
+ 1432*/0x02AE, 2010, 12, 7,/* 0 1 1 1 0 1 0 1 0 1 0 0 12/7/2010
+ 1433*/0x056D, 2011, 11, 26,/* 1 0 1 1 0 1 1 0 1 0 1 0 11/26/2011
+ 1434*/0x036A, 2012, 11, 15,/* 0 1 0 1 0 1 1 0 1 1 0 0 11/15/2012
+ 1435*/0x0B55, 2013, 11, 4,/* 1 0 1 0 1 0 1 0 1 1 0 1 11/4/2013
+ 1436*/0x0AAA, 2014, 10, 25,/* 0 1 0 1 0 1 0 1 0 1 0 1 10/25/2014
+ 1437*/0x094D, 2015, 10, 14,/* 1 0 1 1 0 0 1 0 1 0 0 1 10/14/2015
+ 1438*/0x049D, 2016, 10, 2,/* 1 0 1 1 1 0 0 1 0 0 1 0 10/2/2016
+ 1439*/0x095D, 2017, 9, 21,/* 1 0 1 1 1 0 1 0 1 0 0 1 9/21/2017
+ 1440*/0x02BA, 2018, 9, 11,/* 0 1 0 1 1 1 0 1 0 1 0 0 9/11/2018
+ 1441*/0x05B5, 2019, 8, 31,/* 1 0 1 0 1 1 0 1 1 0 1 0 8/31/2019
+ 1442*/0x05AA, 2020, 8, 20,/* 0 1 0 1 0 1 0 1 1 0 1 0 8/20/2020
+ 1443*/0x0D55, 2021, 8, 9,/* 1 0 1 0 1 0 1 0 1 0 1 1 8/9/2021
+ 1444*/0x0A9A, 2022, 7, 30,/* 0 1 0 1 1 0 0 1 0 1 0 1 7/30/2022
+ 1445*/0x092E, 2023, 7, 19,/* 0 1 1 1 0 1 0 0 1 0 0 1 7/19/2023
+ 1446*/0x026E, 2024, 7, 7,/* 0 1 1 1 0 1 1 0 0 1 0 0 7/7/2024
+ 1447*/0x055D, 2025, 6, 26,/* 1 0 1 1 1 0 1 0 1 0 1 0 6/26/2025
+ 1448*/0x0ADA, 2026, 6, 16,/* 0 1 0 1 1 0 1 1 0 1 0 1 6/16/2026
+ 1449*/0x06D4, 2027, 6, 6,/* 0 0 1 0 1 0 1 1 0 1 1 0 6/6/2027
+ 1450*/0x06A5, 2028, 5, 25,/* 1 0 1 0 0 1 0 1 0 1 1 0 5/25/2028
+ 1451*/0x054B, 2029, 5, 14,/* 1 1 0 1 0 0 1 0 1 0 1 0 5/14/2029
+ 1452*/0x0A97, 2030, 5, 3,/* 1 1 1 0 1 0 0 1 0 1 0 1 5/3/2030
+ 1453*/0x054E, 2031, 4, 23,/* 0 1 1 1 0 0 1 0 1 0 1 0 4/23/2031
+ 1454*/0x0AAE, 2032, 4, 11,/* 0 1 1 1 0 1 0 1 0 1 0 1 4/11/2032
+ 1455*/0x05AC, 2033, 4, 1,/* 0 0 1 1 0 1 0 1 1 0 1 0 4/1/2033
+ 1456*/0x0BA9, 2034, 3, 21,/* 1 0 0 1 0 1 0 1 1 1 0 1 3/21/2034
+ 1457*/0x0D92, 2035, 3, 11,/* 0 1 0 0 1 0 0 1 1 0 1 1 3/11/2035
+ 1458*/0x0B25, 2036, 2, 28,/* 1 0 1 0 0 1 0 0 1 1 0 1 2/28/2036
+ 1459*/0x064B, 2037, 2, 16,/* 1 1 0 1 0 0 1 0 0 1 1 0 2/16/2037
+ 1460*/0x0CAB, 2038, 2, 5,/* 1 1 0 1 0 1 0 1 0 0 1 1 2/5/2038
+ 1461*/0x055A, 2039, 1, 26,/* 0 1 0 1 1 0 1 0 1 0 1 0 1/26/2039
+ 1462*/0x0B55, 2040, 1, 15,/* 1 0 1 0 1 0 1 0 1 1 0 1 1/15/2040
+ 1463*/0x06D2, 2041, 1, 4,/* 0 1 0 0 1 0 1 1 0 1 1 0 1/4/2041
+ 1464*/0x0EA5, 2041, 12, 24,/* 1 0 1 0 0 1 0 1 0 1 1 1 12/24/2041
+ 1465*/0x0E4A, 2042, 12, 14,/* 0 1 0 1 0 0 1 0 0 1 1 1 12/14/2042
+ 1466*/0x0A95, 2043, 12, 3,/* 1 0 1 0 1 0 0 1 0 1 0 1 12/3/2043
+ 1467*/0x052D, 2044, 11, 21,/* 1 0 1 1 0 1 0 0 1 0 1 0 11/21/2044
+ 1468*/0x0AAD, 2045, 11, 10,/* 1 0 1 1 0 1 0 1 0 1 0 1 11/10/2045
+ 1469*/0x036C, 2046, 10, 31,/* 0 0 1 1 0 1 1 0 1 1 0 0 10/31/2046
+ 1470*/0x0759, 2047, 10, 20,/* 1 0 0 1 1 0 1 0 1 1 1 0 10/20/2047
+ 1471*/0x06D2, 2048, 10, 9,/* 0 1 0 0 1 0 1 1 0 1 1 0 10/9/2048
+ 1472*/0x0695, 2049, 9, 28,/* 1 0 1 0 1 0 0 1 0 1 1 0 9/28/2049
+ 1473*/0x052D, 2050, 9, 17,/* 1 0 1 1 0 1 0 0 1 0 1 0 9/17/2050
+ 1474*/0x0A5B, 2051, 9, 6,/* 1 1 0 1 1 0 1 0 0 1 0 1 9/6/2051
+ 1475*/0x04BA, 2052, 8, 26,/* 0 1 0 1 1 1 0 1 0 0 1 0 8/26/2052
+ 1476*/0x09BA, 2053, 8, 15,/* 0 1 0 1 1 1 0 1 1 0 0 1 8/15/2053
+ 1477*/0x03B4, 2054, 8, 5,/* 0 0 1 0 1 1 0 1 1 1 0 0 8/5/2054
+ 1478*/0x0B69, 2055, 7, 25,/* 1 0 0 1 0 1 1 0 1 1 0 1 7/25/2055
+ 1479*/0x0B52, 2056, 7, 14,/* 0 1 0 0 1 0 1 0 1 1 0 1 7/14/2056
+ 1480*/0x0AA6, 2057, 7, 3,/* 0 1 1 0 0 1 0 1 0 1 0 1 7/3/2057
+ 1481*/0x04B6, 2058, 6, 22,/* 0 1 1 0 1 1 0 1 0 0 1 0 6/22/2058
+ 1482*/0x096D, 2059, 6, 11,/* 1 0 1 1 0 1 1 0 1 0 0 1 6/11/2059
+ 1483*/0x02EC, 2060, 5, 31,/* 0 0 1 1 0 1 1 1 0 1 0 0 5/31/2060
+ 1484*/0x06D9, 2061, 5, 20,/* 1 0 0 1 1 0 1 1 0 1 1 0 5/20/2061
+ 1485*/0x0EB2, 2062, 5, 10,/* 0 1 0 0 1 1 0 1 0 1 1 1 5/10/2062
+ 1486*/0x0D54, 2063, 4, 30,/* 0 0 1 0 1 0 1 0 1 0 1 1 4/30/2063
+ 1487*/0x0D2A, 2064, 4, 18,/* 0 1 0 1 0 1 0 0 1 0 1 1 4/18/2064
+ 1488*/0x0A56, 2065, 4, 7,/* 0 1 1 0 1 0 1 0 0 1 0 1 4/7/2065
+ 1489*/0x04AE, 2066, 3, 27,/* 0 1 1 1 0 1 0 1 0 0 1 0 3/27/2066
+ 1490*/0x096D, 2067, 3, 16,/* 1 0 1 1 0 1 1 0 1 0 0 1 3/16/2067
+ 1491*/0x0D6A, 2068, 3, 5,/* 0 1 0 1 0 1 1 0 1 0 1 1 3/5/2068
+ 1492*/0x0B54, 2069, 2, 23,/* 0 0 1 0 1 0 1 0 1 1 0 1 2/23/2069
+ 1493*/0x0B29, 2070, 2, 12,/* 1 0 0 1 0 1 0 0 1 1 0 1 2/12/2070
+ 1494*/0x0A93, 2071, 2, 1,/* 1 1 0 0 1 0 0 1 0 1 0 1 2/1/2071
+ 1495*/0x052B, 2072, 1, 21,/* 1 1 0 1 0 1 0 0 1 0 1 0 1/21/2072
+ 1496*/0x0A57, 2073, 1, 9,/* 1 1 1 0 1 0 1 0 0 1 0 1 1/9/2073
+ 1497*/0x0536, 2073, 12, 30,/* 0 1 1 0 1 1 0 0 1 0 1 0 12/30/2073
+ 1498*/0x0AB5, 2074, 12, 19,/* 1 0 1 0 1 1 0 1 0 1 0 1 12/19/2074
+ 1499*/0x06AA, 2075, 12, 9,/* 0 1 0 1 0 1 0 1 0 1 1 0 12/9/2075
+ 1500*/0x0E93, 2076, 11, 27,/* 1 1 0 0 1 0 0 1 0 1 1 1 11/27/2076
+ 1501*/ 0, 2077, 11, 17,/* 0 0 0 0 0 0 0 0 0 0 0 0 11/17/2077
+ */ };
+ // Direct inline initialization of DateMapping array would produce a lot of code bloat.
+
+ // We take advantage of C# compiler compiles inline initialization of primitive type array into very compact code.
+ // So we start with raw data stored in primitive type array, and initialize the DateMapping out of it
+
+ DateMapping[] mapping = new DateMapping[rawData.Length / 4];
+ for (int i = 0; i < mapping.Length; i++)
+ mapping[i] = new DateMapping(rawData[i * 4], rawData[i * 4 + 1], rawData[i * 4 + 2], rawData[i * 4 + 3]);
+ return mapping;
+ }
+
+ public const int UmAlQuraEra = 1;
+
+ internal const int DateCycle = 30;
+ internal const int DatePartYear = 0;
+ internal const int DatePartDayOfYear = 1;
+ internal const int DatePartMonth = 2;
+ internal const int DatePartDay = 3;
+
+
+ // This is the minimal Gregorian date that we support in the UmAlQuraCalendar.
+ internal static DateTime minDate = new DateTime(1900, 4, 30);
+ internal static DateTime maxDate = new DateTime((new DateTime(2077, 11, 16, 23, 59, 59, 999)).Ticks + 9999);
+
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ public UmAlQuraCalendar()
+ {
+ }
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ return (CalendarId.HIJRI);
+ }
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.UMALQURA);
+ }
+ }
+
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // HijriCalendar has same number of days as UmAlQuraCalendar for any given year
+ // HijriCalendar says year 1317 has 355 days.
+ return 355;
+ }
+ }
+
+ /*==========================ConvertHijriToGregorian==========================
+ ** Purpose: convert Hdate(year,month,day) to Gdate(year,month,day)
+ ** Arguments:
+ ** Input/Ouput: Hijrah date: year:yh, month:mh, day:dh
+ ** Output: Gregorian date: year:yg, month:mg, day:dg , day of week:dayweek
+ ** and returns flag found:1 not found:0
+ =========================ConvertHijriToGregorian============================*/
+ private static void ConvertHijriToGregorian(int HijriYear, int HijriMonth, int HijriDay, ref int yg, ref int mg, ref int dg)
+ {
+ Contract.Assert((HijriYear >= MinCalendarYear) && (HijriYear <= MaxCalendarYear), "Hijri year is out of range.");
+ Contract.Assert(HijriMonth >= 1, "Hijri month is out of range.");
+ Contract.Assert(HijriDay >= 1, "Hijri day is out of range.");
+ int index, b, nDays = HijriDay - 1;
+ DateTime dt;
+
+
+ index = HijriYear - MinCalendarYear;
+ dt = s_hijriYearInfo[index].GregorianDate;
+
+
+ b = s_hijriYearInfo[index].HijriMonthsLengthFlags;
+
+ for (int m = 1; m < HijriMonth; m++)
+ {
+ nDays = nDays + 29 + (b & 1); /* Add the months lengths before mh */
+ b = b >> 1;
+ }
+
+ dt = dt.AddDays(nDays);
+ yg = dt.Year;
+ mg = dt.Month;
+ dg = dt.Day;
+ }
+
+ /*=================================GetAbsoluteDateUmAlQura==========================
+ **Action: Gets the Absolute date for the given UmAlQura date. The absolute date means
+ ** the number of days from January 1st, 1 A.D.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+ private static long GetAbsoluteDateUmAlQura(int year, int month, int day)
+ {
+ //Caller should check the validaty of year, month and day.
+
+ int yg = 0, mg = 0, dg = 0;
+ ConvertHijriToGregorian(year, month, day, ref yg, ref mg, ref dg);
+ return GregorianCalendar.GetAbsoluteDate(yg, mg, dg);
+ }
+
+ internal static void CheckTicksRange(long ticks)
+ {
+ if (ticks < minDate.Ticks || ticks > maxDate.Ticks)
+ {
+ throw new ArgumentOutOfRangeException(
+ "time",
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.ArgumentOutOfRange_CalendarRange,
+ minDate,
+ maxDate));
+ }
+ }
+
+ internal static void CheckEraRange(int era)
+ {
+ if (era != CurrentEra && era != UmAlQuraEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+ }
+
+ internal static void CheckYearRange(int year, int era)
+ {
+ CheckEraRange(era);
+ if (year < MinCalendarYear || year > MaxCalendarYear)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MinCalendarYear,
+ MaxCalendarYear));
+ }
+ }
+
+ internal static void CheckYearMonthRange(int year, int month, int era)
+ {
+ CheckYearRange(year, era);
+ if (month < 1 || month > 12)
+ {
+ throw new ArgumentOutOfRangeException("month", SR.ArgumentOutOfRange_Month);
+ }
+ }
+
+ /*========================ConvertGregorianToHijri============================
+ ** Purpose: convert DateTime to Hdate(year,month,day)
+ ** Arguments:
+ ** Input: DateTime
+ ** Output: Hijrah date: year:yh, month:mh, day:dh
+ ============================================================================*/
+ private static void ConvertGregorianToHijri(DateTime time, ref int HijriYear, ref int HijriMonth, ref int HijriDay)
+ {
+ int index, b, DaysPerThisMonth;
+ double nDays;
+ TimeSpan ts;
+ int yh1 = 0, mh1 = 0, dh1 = 0;
+
+ Contract.Assert((time.Ticks >= minDate.Ticks) && (time.Ticks <= maxDate.Ticks), "Gregorian date is out of range.");
+
+ // Find the index where we should start our search by quessing the Hijri year that we will be in HijriYearInfo.
+ // A Hijri year is 354 or 355 days. Use 355 days so that we will search from a lower index.
+
+ index = (int)((time.Ticks - minDate.Ticks) / Calendar.TicksPerDay) / 355;
+ do
+ {
+ } while (time.CompareTo(s_hijriYearInfo[++index].GregorianDate) > 0); //while greater
+
+ if (time.CompareTo(s_hijriYearInfo[index].GregorianDate) != 0)
+ {
+ index--;
+ }
+
+ ts = time.Subtract(s_hijriYearInfo[index].GregorianDate);
+ yh1 = index + MinCalendarYear;
+
+ mh1 = 1;
+ dh1 = 1;
+ nDays = ts.TotalDays;
+ b = s_hijriYearInfo[index].HijriMonthsLengthFlags;
+ DaysPerThisMonth = 29 + (b & 1);
+
+ while (nDays >= DaysPerThisMonth)
+ {
+ nDays -= DaysPerThisMonth;
+ b = b >> 1;
+ DaysPerThisMonth = 29 + (b & 1);
+ mh1++;
+ }
+ dh1 += (int)nDays;
+
+ HijriDay = dh1;
+ HijriMonth = mh1;
+ HijriYear = yh1;
+ }
+
+ /*=================================GetDatePart==========================
+ **Action: Returns a given date part of this <i>DateTime</i>. This method is used
+ ** to compute the year, day-of-year, month, or day part.
+ **Returns:
+ **Arguments:
+ **Exceptions: ArgumentException if part is incorrect.
+ **Notes:
+ ** First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks.
+ ** Use the formula (((AbsoluteDate - 226894) * 33) / (33 * 365 + 8)) + 1, we can a rough value for the UmAlQura year.
+ ** In order to get the exact UmAlQura year, we compare the exact absolute date for UmAlQuraYear and (UmAlQuraYear + 1).
+ ** From here, we can get the correct UmAlQura year.
+ ============================================================================*/
+
+ internal virtual int GetDatePart(DateTime time, int part)
+ {
+ int UmAlQuraYear = 0; // UmAlQura year
+ int UmAlQuraMonth = 0; // UmAlQura month
+ int UmAlQuraDay = 0; // UmAlQura day
+ long ticks = time.Ticks;
+ CheckTicksRange(ticks);
+
+ ConvertGregorianToHijri(time, ref UmAlQuraYear, ref UmAlQuraMonth, ref UmAlQuraDay);
+
+ if (part == DatePartYear)
+ return (UmAlQuraYear);
+
+ if (part == DatePartMonth)
+ return (UmAlQuraMonth);
+
+ if (part == DatePartDay)
+ return (UmAlQuraDay);
+
+ if (part == DatePartDayOfYear)
+ return (int)(GetAbsoluteDateUmAlQura(UmAlQuraYear, UmAlQuraMonth, UmAlQuraDay) - GetAbsoluteDateUmAlQura(UmAlQuraYear, 1, 1) + 1);
+
+ // Incorrect part value.
+ throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing);
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+
+ public override DateTime AddMonths(DateTime time, int months)
+ {
+ if (months < -120000 || months > 120000)
+ {
+ throw new ArgumentOutOfRangeException(
+ "months",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ -120000,
+ 120000));
+ }
+ Contract.EndContractBlock();
+ // Get the date in UmAlQura calendar.
+ int y = GetDatePart(time, DatePartYear);
+ int m = GetDatePart(time, DatePartMonth);
+ int d = GetDatePart(time, DatePartDay);
+ int i = m - 1 + months;
+
+ if (i >= 0)
+ {
+ m = i % 12 + 1;
+ y = y + i / 12;
+ }
+ else
+ {
+ m = 12 + (i + 1) % 12;
+ y = y + (i - 11) / 12;
+ }
+
+ if (d > 29)
+ {
+ int days = GetDaysInMonth(y, m);
+ if (d > days)
+ {
+ d = days;
+ }
+ }
+ CheckYearRange(y, UmAlQuraEra);
+ DateTime dt = new DateTime(GetAbsoluteDateUmAlQura(y, m, d) * TicksPerDay + time.Ticks % TicksPerDay);
+ Calendar.CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (dt);
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+
+ public override DateTime AddYears(DateTime time, int years)
+ {
+ return (AddMonths(time, years * 12));
+ }
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+
+ public override int GetDayOfMonth(DateTime time)
+ {
+ return (GetDatePart(time, DatePartDay));
+ }
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+
+ public override DayOfWeek GetDayOfWeek(DateTime time)
+ {
+ return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
+ }
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 354 or 355.
+ //
+
+
+ public override int GetDayOfYear(DateTime time)
+ {
+ return (GetDatePart(time, DatePartDayOfYear));
+ }
+
+ /*
+ internal bool CouldBeLeapYear(int year)
+ {
+ return ((((year * 11) + 14) % 30) < 11);
+ }
+ */
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+
+ public override int GetDaysInMonth(int year, int month, int era)
+ {
+ CheckYearMonthRange(year, month, era);
+
+ if ((s_hijriYearInfo[year - MinCalendarYear].HijriMonthsLengthFlags & (1 << month - 1)) == 0)
+ return 29;
+ else
+ return 30;
+ }
+
+ internal static int RealGetDaysInYear(int year)
+ {
+ int days = 0, b;
+
+ Contract.Assert((year >= MinCalendarYear) && (year <= MaxCalendarYear), "Hijri year is out of range.");
+
+ b = s_hijriYearInfo[year - MinCalendarYear].HijriMonthsLengthFlags;
+
+ for (int m = 1; m <= 12; m++)
+ {
+ days = days + 29 + (b & 1); /* Add the months lengths before mh */
+ b = b >> 1;
+ }
+ Contract.Assert((days == 354) || (days == 355), "Hijri year has to be 354 or 355 days.");
+ return days;
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+
+ public override int GetDaysInYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return (RealGetDaysInYear(year));
+ }
+
+ // Returns the era for the specified DateTime value.
+
+
+ public override int GetEra(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return (UmAlQuraEra);
+ }
+
+
+
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { UmAlQuraEra });
+ }
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+
+ public override int GetMonth(DateTime time)
+ {
+ return (GetDatePart(time, DatePartMonth));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+
+ public override int GetMonthsInYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return (12);
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between MinCalendarYear and MaxCalendarYear.
+ //
+
+
+ public override int GetYear(DateTime time)
+ {
+ return (GetDatePart(time, DatePartYear));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+
+ public override bool IsLeapDay(int year, int month, int day, int era)
+ {
+ if (day >= 1 && day <= 29)
+ {
+ CheckYearMonthRange(year, month, era);
+ return (false);
+ }
+
+ // The year/month/era value checking is done in GetDaysInMonth().
+ int daysInMonth = GetDaysInMonth(year, month, era);
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Day,
+ daysInMonth,
+ month));
+ }
+ return (false);
+ }
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+
+ public override int GetLeapMonth(int year, int era)
+ {
+ CheckYearRange(year, era);
+ return (0);
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+
+ public override bool IsLeapMonth(int year, int month, int era)
+ {
+ CheckYearMonthRange(year, month, era);
+ return (false);
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+
+ public override bool IsLeapYear(int year, int era)
+ {
+ CheckYearRange(year, era);
+ if (RealGetDaysInYear(year) == 355)
+ return true;
+ else
+ return false;
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+
+ public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
+ {
+ if (day >= 1 && day <= 29)
+ {
+ CheckYearMonthRange(year, month, era);
+ goto DayInRang;
+ }
+
+ // The year/month/era value checking is done in GetDaysInMonth().
+ int daysInMonth = GetDaysInMonth(year, month, era);
+
+ if (day < 1 || day > daysInMonth)
+ {
+ throw new ArgumentOutOfRangeException(
+ "day",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Day,
+ daysInMonth,
+ month));
+ }
+ DayInRang:
+ long lDate = GetAbsoluteDateUmAlQura(year, month, day);
+
+ if (lDate >= 0)
+ {
+ return (new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond)));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
+ }
+ }
+
+ private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 1451;
+
+
+
+ public override int TwoDigitYearMax
+ {
+ get
+ {
+ if (twoDigitYearMax == -1)
+ {
+ twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
+ }
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ if (value != 99 && (value < MinCalendarYear || value > MaxCalendarYear))
+ {
+ throw new ArgumentOutOfRangeException(
+ "value",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MinCalendarYear,
+ MaxCalendarYear));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ // We allow year 99 to be set so that one can make ToFourDigitYearMax a no-op by setting TwoDigitYearMax to 99.
+ twoDigitYearMax = value;
+ }
+ }
+
+
+
+ public override int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+
+ if (year < 100)
+ {
+ return (base.ToFourDigitYear(year));
+ }
+
+ if ((year < MinCalendarYear) || (year > MaxCalendarYear))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range,
+ MinCalendarYear,
+ MaxCalendarYear));
+ }
+ return (year);
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/UnicodeCategory.cs b/src/mscorlib/corefx/System/Globalization/UnicodeCategory.cs
new file mode 100644
index 0000000000..1c5e6bca56
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/UnicodeCategory.cs
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Globalization
+{
+ [Serializable]
+ public enum UnicodeCategory
+ {
+ UppercaseLetter = 0,
+
+ LowercaseLetter = 1,
+
+ TitlecaseLetter = 2,
+
+ ModifierLetter = 3,
+
+ OtherLetter = 4,
+
+ NonSpacingMark = 5,
+
+ SpacingCombiningMark = 6,
+
+ EnclosingMark = 7,
+
+ DecimalDigitNumber = 8,
+
+ LetterNumber = 9,
+
+ OtherNumber = 10,
+
+ SpaceSeparator = 11,
+
+ LineSeparator = 12,
+
+ ParagraphSeparator = 13,
+
+ Control = 14,
+
+ Format = 15,
+
+ Surrogate = 16,
+
+ PrivateUse = 17,
+
+ ConnectorPunctuation = 18,
+
+ DashPunctuation = 19,
+
+ OpenPunctuation = 20,
+
+ ClosePunctuation = 21,
+
+ InitialQuotePunctuation = 22,
+
+ FinalQuotePunctuation = 23,
+
+ OtherPunctuation = 24,
+
+ MathSymbol = 25,
+
+ CurrencySymbol = 26,
+
+ ModifierSymbol = 27,
+
+ OtherSymbol = 28,
+
+ OtherNotAssigned = 29,
+ }
+}